I have a templated C++ class that exposes a number of methods, e.g
template<int X, int Y>
class MyBuffer {
public:
MyBuffer<X,Y> method1();
};
Now, I want to expose additional methods to this class if X == Y. I have done this by subclassing MyBuffer,
template<int X>
class MyRegularBuffer : public MyBuffer<X,X> {
public:
MyRegularBuffer method2();
};
Now, the problem is that I want to be able to do e.g.
MyRegularBuffer<2> buf = ...
MyRegularBuffer<2> otherBuf = buf.method1().method2();
But I am not sure how to accomplish this. I tried to think of copy constructors, conversion operators, etc, but my C++ skills are unfortunately a bit rusty.
EDIT: I should add that creation of these objects is relatively cheap (and also, it won't happen a lot), which means it would be OK to do something like this:
MyRegularBuffer<2> buf = ...
MyRegularBuffer<2> temp = buf.method1(); // Implicit conversion
MyRegularBuffer<2> otherBuf = temp.method2();
The question is then, how can I define the conversion like that. The conversion operator needs to be in MyBuffer, I think, but I want it to be available only if X==Y.
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.
You can choose to specialize only some of the parameters of a class template. This is known as partial specialization. Note that function templates cannot be partially specialized; use overloading to achieve the same effect.
An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.
It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.
I'd go for CRTP here:
template<int X, int Y, class Derived>
struct MyBufferBase {
// common interface:
Derived& method1() { return *static_cast<Derived*>(this); }
};
template<int X, int Y>
struct MyBuffer : MyBufferBase<X, Y, MyBuffer<X,Y> > {
// basic version
};
template<int X>
struct MyRegularBuffer : MyBufferBase<X, X, MyRegularBuffer<X> > {
// extended interface:
MyRegularBuffer& method2() { return *this; }
};
You don't need a separate class to represent the special behaviour. Partial specialization allows you to treat some of the MyBuffer <X,Y> cases specially and give them extra methods.
Keep your original declaration of MyBuffer<X,Y> and add this:
template<int Y>
class MyBuffer<Y, Y> {
public:
MyBuffer<Y,Y> method1();
MyBuffer<Y,Y> method2();
};
MyBuffer<1,2> m12; m12.method2(); // compile fail, as desired, as it doesn't have such a method because 1 != 2
MyBuffer<2,2> m22; m22.method2(); // compile success
Edit: my final lines weren't very useful after all, as pointed out by Georg in the comments, so I've deleted them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With