I have a templated C++ class that exposes a number of methods, eg
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 eg
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.
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.
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; }
};
It's possible to do what you want if method1
and method2
return a reference to *this
. Otherwise, you're going to need to either do a conversion, or make method1
virtual.
The trick is to have a MyRegularBuffer::method1
that calls MyBuffer::method1
, then a way to convert the resultant MyBuffer<X,X>
into a MyRegularBuffer<X>
:
template<int X>
class MyRegularBuffer : public MyBuffer<X,X>
{
public:
MyRegularBuffer<X>()
{}
MyRegularBuffer<X>(MyBuffer<X,X>)
{
// copy fields, or whatever
}
MyRegularBuffer<X> method2();
MyRegularBuffer<X> method1()
{
MyRegularBuffer<X> ret(MyBuffer<X,X>::method1());
return(ret);
}
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.