2010-07-29 2 views
6

У меня есть шаблонный класс 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++, к сожалению, немного ржавые.

EDIT: Я хотел бы добавить, что создание этих объектов является относительно дешевым (а также, что не будет много), что означает, что было бы хорошо, чтобы сделать что-то вроде этого:

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

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

+1

Совершенно непонятное. Например, вы говорите о «операторе преобразования», но его нет. Отправьте некоторый реальный код. – 2010-07-29 21:15:06

+0

@Neil, я думаю, пользователь задал неподдельный вопрос в меру своих возможностей. И я думаю, что я это понимаю. –

+0

@Aaron В этом случае, сообщите пожалуйста. – 2010-07-29 22:36:30

ответ

5

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

Держите оригинальную декларацию MyBuffer < X, Y > и добавить:

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: мои последние строки не были очень полезны в конце концов, как отметил Georg в комментариях, поэтому я удалил их.

+1

Единственным недостатком является то, что метод method1() должен быть повторно реализован в MyBuffer , иначе компилятор будет жаловаться на неизвестный метод при попытке вызвать MyBuffer :: method1(). AFAIK, нет способа иметь MyBuffer :: method1() делегировать его реализацию MyBuffer :: method1() без указания различных параметров шаблона, где X! = Y. –

+0

Вывод из 'MyBuffer' не будет работать - это не так Не знаю производного класса и, следовательно, не может вернуть соответствующий тип из 'method1()'. –

+0

@Georg, я не понимаю. Можете ли вы уточнить, какая линия будет терпеть неудачу? Я скомпилировал свой код, и он работает. Но я должен признать, что я скорректировал самую последнюю строку неправильно о «классе MyRegularBuffer». Сейчас обновится. –

1

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

+0

Даже если метод method1() возвращает это, вы все равно не можете вызывать метод method2() из его возвращаемого значения, потому что метод2() не является частью интерфейса MyBuffer . – wilhelmtell

+0

Не могли бы вы подробно остановиться на подходе к виртуальному методу? Я не уверен, что получил это ... Проблема, с которой я столкнулся, - это контракт, реализация будет одинаковой (объект идентичен в памяти, если X == Y, поэтому я мог бы просто сделать переинтерпретацию). – Krumelur

+0

wilhelmtell, да, именно то, что я имел в виду. Вы были быстрее :) – Krumelur

1

Хитрость заключается в том, чтобы иметь 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); 
    } 
}; 
+0

Спасибо. Да, это хорошая идея, но в моем случае это ничего не добавляет к решению @Aaron McDaid, поскольку мне нужно снова реализовать метод1 (метод1 на самом деле представляет собой ряд методов). – Krumelur

3

я бы на 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; } 
}; 
+0

+1 Спасибо, что напомнили мне об этом. –

+0

Спасибо за это. Это абсолютно хорошая идея. – Krumelur

+0

Я бы отметил как ответ, если бы мог дать оценку более чем одному ответу, но сейчас решение Аарона МакДэйда действительно выпадает довольно хорошо, так как мои методы довольно тонкие (это класс-оболочка). – Krumelur

Смежные вопросы