A common technique is to have a class template where the template argument simply serves as a unique token (“tag”) to make it a unique type:
template <typename Tag>
class Fruit {
int p;
public:
Fruit(int p) : p(p) { }
int price() const { return p; }
};
using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;
Note that the tag classes don’t even need to be defined, it’s enough to declare a unique type name. This works because the tag isn’s actually used anywhere in the template. And you can declare the type name inside the template argument list (hat tip to @Xeo).
The using
syntax is C++11. If you’re stuck with C++03, write this instead:
typedef Fruit<struct AppleTag> Apple;
If the common functionality takes up a lot of code this unfortunately introduces quite a lot of duplicate code in the final executable. This can be prevented by having a common base class implementing the functionality, and then having a specialisation (that you actually instantiate) that derives from it.
Unfortunately, that requires you to re-implement all non-inheritable members (constructors, assignment …) which adds a small overhead itself – so this only makes sense for large classes. Here it is applied to the above example:
// Actual `Fruit` class remains unchanged, except for template declaration
template <typename Tag, typename = Tag>
class Fruit { /* unchanged */ };
template <typename T>
class Fruit<T, T> : public Fruit<T, void> {
public:
// Should work but doesn’t on my compiler:
//using Fruit<T, void>::Fruit;
Fruit(int p) : Fruit<T, void>(p) { }
};
using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…