Consider the following situation: you have data to process that naturally uses the same container for storage yet needs to be processed differently based on the data "type". For example, say you are processing digital audio data and that data comes in the following formats:
- Linear PCM (Pulse Code Modulation) - WAV audio content
- ?-Law PCM - American telephone standard
- a-Law PCM - European telephone standard
Let's say all three use 8bit samples and have the same number of samples per packet. This type of data naturally uses a std::vector
for storage. We could pass this data to a hypothetical class AudioPlayer
:
- with a tag to indicate how to play it on the speakers. That means we have to couple the tag with the
std::vector
as is passes through the program. - Create a common base class and inherit three distinct derived classes that only differ in that they are different classes. With each new audio packet type we need to derive a new class with no real differences from the other.
- Use non-type template parameter to create a unique type.
What is a "non-type template parameter?" C++98 allows you to pass an integer value as a template parameter. Instantiated templates with different integer values are different classes. We can overload on these different classes. While it is still necessary to create an overload for each new audio type (kinda the point...), creating a distinct class for that overload is now trivial.
[cpp title="Example of Non-Type Template Parameter"]
template
class AudioPacket : public AudioPacket
{
public:
typedef T value_type;
static const int TypeIndex=I;
};
typedef std::vector Audio;
typedef AudioPacket LinearPCM;
typedef AudioPacket MuLawPCM;
typedef AudioPacket ALawPCM;
// this class is just a sketch
class AudioRender {
public:
void play(const LinearPCM& audio);
void play(const MuLawPCM& audio);
void play(const ALawPCM& audio);
};
[/cpp]
We also used the Curiously Recurring Template Pattern is used to provide static polymorphism. The trick is that the types must be resolvable at compile time. This is actually a better explanation of CRTP.
We'll look more closely at CRTP and static polymorphism in the future.