2016-05-05 6 views
1

Я хотел бы определить класс шаблона со специализацией некоторых методов для разных типов.Использовать шаблон с базовым классом как параметр

template <typename T> 
class Handler { 
public: 
    void method1() { method2(); } 
protected: 
    void method2(); 
} 

Затем в файле реализации:

template <> Handler<int>::method2() { doSomething(); } 
template <> Handler<float>::method2() { doSomethingElse(); } 
template <> Handler<ClassB>::method2() { doSomethingDifferent(); } 

До сих пор все работает нормально.

Теперь я хотел бы определить некоторые новые классы, полученные из ClassB, и использовать специализированную специализацию по объектам этих классов. Конечно, он компилируется, но не связывается, потому что специализация для каждого подкласса отсутствует.

Есть ли способ использовать шаблон для них, например, используя SFINAE?

+0

Вы можете включать в свой код шаблона в файле заголовка - Thats, вероятно, не то, что вы ищет хотя – tobspr

+0

Специализация шаблона концептуально отличается от наследования. У вас не может быть шаблон с функцией-членом, которая не определена, и ожидать, что она будет работать так. Возможно, вы ищете [CRTP] (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)? Если нет, пожалуйста, уточните, чего вы пытаетесь достичь. – jPlatte

ответ

2

Я часто перегружать на тип тега хороший alterantive специализации:

namespace { 

template<class T> struct Type { using type = T; }; // Or boost::type<T> 
template<class T> struct TypeTag { using type = Type<T>; }; 

struct ClassB {}; 

template <typename T> 
class Handler { 
public: 
    void method1() { 
     method2(typename TypeTag<T>::type{}); // Call an overloaded function. 
    } 
protected: 
    void method2(Type<int>) { std::printf("%s\n", __PRETTY_FUNCTION__); } 
    void method2(Type<float>) { std::printf("%s\n", __PRETTY_FUNCTION__); } 
    void method2(Type<ClassB>) { std::printf("%s\n", __PRETTY_FUNCTION__); } 
}; 

// Somewhere else. 
struct ClassC : ClassB {}; 
template<> struct TypeTag<ClassC> { using type = Type<ClassB>; }; 

} // namespace 

int main(int ac, char**) { 
    Handler<ClassB> b; 
    b.method1(); 

    Handler<ClassC> c; 
    c.method1(); 
} 

Выходы:

void {anonymous}::Handler<T>::method2({anonymous}::Type<{anonymous}::ClassB>) [with T = {anonymous}::ClassB] 
void {anonymous}::Handler<T>::method2({anonymous}::Type<{anonymous}::ClassB>) [with T = {anonymous}::ClassC] 
+1

Я собираюсь попробовать. Это похоже на классическое решение, использующее дополнительный уровень косвенности. –

+0

@GB Да, ваше наблюдение находится на месте. Другой способ взглянуть на это - это сопоставление всех типов с несколькими определенными категориями. 'TypeTag ' maps type 'T' в категорию' TypeTag :: type'. Специализация 'TypeTag ' позволяет определить категорию для любого типа. –

1

Первое:

template <class T,class=void> 
class Handler 

затем использовать SFINAE создать специализацию:

template <class T> 
class Handler<T,std::enable_if_t<test>> 

Теперь у этой специализации либо включить его реализацию в своем теле, или наследовать от типа реализации (не шаблон) и реализовать это в файле impl.

Для ваших puroos, испытание может быть основанием.

Ваш int impl теперь нуждается в добавленном параметре ,void.

Вы также можете использовать класс признаков для условного сопоставления.