简体   繁体   中英

Adding methods to template specialization

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM