Добавление методов к специализации шаблона - PullRequest
6 голосов
/ 30 июля 2010

У меня есть шаблонный класс C ++, который предоставляет ряд методов, например,

template<int X, int Y>
class MyBuffer {
public:
    MyBuffer<X,Y> method1();
};

Теперь я хочу предоставить дополнительные методы этому классу, если X == Y. Я сделал это, создав подкласс MyBuffer,

template<int X>
class MyRegularBuffer : public MyBuffer<X,X> {
public:
    MyRegularBuffer method2();
};

Теперь проблема в том, что я хочу быть в состоянии сделать, например,

MyRegularBuffer<2> buf = ...
MyRegularBuffer<2> otherBuf = buf.method1().method2();

Но я не уверен, как этого добиться. Я пытался думать о конструкторах копирования, операторах преобразования и т. Д., Но мои навыки в C ++, к сожалению, немного устарели.

РЕДАКТИРОВАТЬ: я должен добавить, что создание этих объектов является относительно дешевым (а также, это не произойдет много), что означает, что было бы нормально сделать что-то вроде этого:

MyRegularBuffer<2> buf = ...
MyRegularBuffer<2> temp = buf.method1(); // Implicit conversion
MyRegularBuffer<2> otherBuf = temp.method2();

Тогда возникает вопрос, как я могу определить преобразование таким образом? Я думаю, что оператор преобразования должен быть в MyBuffer, но я хочу, чтобы он был доступен, только если X == Y.

Ответы [ 4 ]

5 голосов
/ 30 июля 2010

Вам не нужен отдельный класс для представления особого поведения.Частичная специализация позволяет вам относиться к некоторым из MyBufferв особых случаях и предоставьте им дополнительные методы.

Сохраните исходное объявление MyBufferи добавьте это:

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

Редактировать: мои последние строки были не очень полезны, как указал Георг в комментариях, поэтому я удалил их.

3 голосов
/ 30 июля 2010

Я бы пошел на CRTP здесь:

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; }
};
1 голос
/ 30 июля 2010

Хитрость заключается в том, чтобы иметь MyRegularBuffer::method1, который вызывает MyBuffer::method1, а затем способ преобразовать результирующее MyBuffer<X,X> в 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);
  }
};
1 голос
/ 30 июля 2010

Можно сделать то, что вы хотите, если method1 и method2 вернут ссылку на *this. В противном случае вам нужно будет либо выполнить преобразование, либо сделать method1 виртуальным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...