2015-03-13 4 views
2

Рассмотрим два частичных специализаций ниже:Специализации, которые структурно идентичны

#include <iostream> 
#include <vector> 
#include <type_traits> 

template <typename, typename...> struct A; 

template <typename... Ts> 
struct A<int, Ts...> { 
    void foo (int a) const {std::cout << a << '\n';} 
    void operator()(const std::vector<int>& v) const {std::cout << v.size() << '\n';} 
}; 

template <typename... Ts> 
struct A<char, Ts...> { 
    void foo (char a) const {std::cout << a << '\n';} 
    void operator()(const std::vector<char>& v) const {std::cout << v.size() << '\n';} 
}; 

int main() { 
    A<int, long, double> a; 
    A<char, float, bool, short> b; 
    a.foo(5); // 5 
    b.foo('!'); // ! 
    a({1,2,3}); // 3 
    b({1,2,3}); // 3 
} 

Как написать два специализаций только один раз?

template <typename T, typename... Ts> 
struct A<T, Ts...> { 
    static_assert (std::is_same<T,int>::value || std::is_same<T,char>::value, "Error"); 
    void foo (T a) const {std::cout << a << '\n';} 
    void operator()(const std::vector<T>& v) const {std::cout << v.size() << '\n';} 
}; 

не работает, потому что ничего не специализироваться, и я не могу поставить class = std::enable_if<std::is_same<T,int>::value || std::is_same<T,char>::value, T>::type в любом месте, потому что по умолчанию аргумент а не может пойти после обновления. Вышеупомянутые специализации должны быть только для int и char. Любой другой тип будет некоторым другим общим определением для класса.

+2

Переместите идентичную часть в отдельный шаблон, затем используйте наследование. –

ответ

1

Я думаю, что это лучше.

template <typename T> struct B 
{ 
    void foo (T a) const 
    { 
     std::cout << a << '\n'; 
    } 
    void operator()(const std::vector<T>& v) const 
    { 
     std::cout << v.size() << '\n'; 
    } 

}; 

template <typename T, typename... Ts> 
struct A {}; 

template <typename... Ts> 
struct A<int,Ts...> :public B<int> 
    {}; 
template <typename... Ts> 
struct A<char,Ts...> :public B<char> 
    {}; 


int main() 
{ 
    A<int, long, double> a; 
    A<char, float, bool, short> b; 
    a.foo(5); // 5 
    b.foo('!'); // ! 
    a({1,2,3}); // 3 
    b({1,2,3}); // 3 
} 

Этот способ более прост и чист.

+0

Но я хочу эту форму только для T = int и T = char. Любой другой T должен иметь другую форму для структуры. – prestokeys

+0

@prestokeys - это хорошо? В вашем шаблоне B не требуется Ts ... –

+0

Да, вы правы. Но в моем программном коде мой класс «A » на самом деле получен из другого класса шаблонов, который имеет «Ts ...», поэтому мой класс «B » действительно нуждается в «Ts ...», потому что он помещается между двумя классов и использует 'Ts ...' в своем operator(). Но ваше решение получает мой голос. – prestokeys

1

Спасибо, к Агар Т.С., как всегда:

#include <iostream> 
#include <vector> 
#include <type_traits> 

template <typename, typename...> struct A; 

template <typename T, typename... Ts> 
struct B { 
    void foo (T a) const {std::cout << a << '\n';} 
    void operator()(const std::vector<T>& v) const {std::cout << v.size() << '\n';} 
}; 

template <typename... Ts> 
struct A<int, Ts...> : B<int, Ts...> {}; 

template <typename... Ts> 
struct A<char, Ts...> : B<char, Ts...> {}; 


int main() { 
    A<int, long, double> a; 
    A<char, float, bool, short> b; 
    a.foo(5); // 5 
    b.foo('!'); // ! 
    a({1,2,3}); // 3 
    b({1,2,3}); // 3 
}