2015-11-02 4 views
1

Я пытаюсь написать функцию, которая принимает переменное количество аргументов переменных типов. Типы всегда будут POD, за исключением одного случая, когда будет список POD. Я получил это с расширением пакета и рекурсивными вызовами функций шаблона.C++ function template specialization

Эта функция в настоящее время работает для всех переопределений POD с помощью специализации по шаблону, но я хочу создать специализированную специализацию для списка, но сохранить шаблон в шаблоне. Я понимаю, что это может быть невозможно, так как это фактически частичная специализация на уровне функции. Мне интересно об обходных решениях для такого сценария.

Вот что я делаю.

template<typename T, typename ...TArgs> 
void Params2(T value, TArgs... args) { 
     Params2(value); 
     Params2(args...); 
} 
template<typename T> 
inline void Params2(T c) { //invalid msg } 

template <> inline void Params2<unsigned char>(unsigned char c) { //do something with char } 
template <> inline void Params2<char>(char c) { //do something with uchar } 
template <> inline void Params2<unsigned short>(unsigned short c) { //do something with short } 
template <> inline void Params2<short>(short c) { //do something with ushort } 

// more POD overrides 

Если я делаю следующее, это работает, потому что я полностью определен тип списка:

template <> 
inline void Params2< libfc::List<int> >(libfc::List<int> l) 
{ 
    for (auto itt = l.Begin(); itt != l.End(); ++itt) 
    { 
     //do something with each int 
    } 
} 

, что я хочу быть в состоянии сделать это:

template <> 
template <typename R> 
inline void Params2<libfc::List<R> >(libfc::List<R>) { 
    //do something with for each element of type R 
} 

Я бы предпочел не делать переопределение для каждого типа списка, который может выполнять функция, но я могу согласиться с тем, что если нет лучшего варианта.

редактировать: Вызывающее приложение будет вызывать эту функцию вдоль линий (не действительный код, просто пример):

Params2(10, 25, "test", List<int> { 5, 10 }, List<double> { 3.14, 9.81 }); 

ответ

1

Использование перегрузки вместо специализации

inline void Params2(unsigned char c) { //do something with char } 
inline void Params2(char c) { //do something with uchar } 
inline void Params2(unsigned short c) { //do something with short } 
inline void Params2(short c) { //do something with ushort } 

template<typename T> 
void Params2(const std::list<T>& value) { 
// list 
} 


template<typename T, typename ...TArgs> 
void Params2(T value, TArgs... args) { 
     Params2(value); 
     Params2(args...); 
} 

или использовать общий метод и класс специализации

template<typename T> 
struct helper; 

template<> 
struct helper<unsigned char> { void operator() (unsigned char c) { /**/}}; 
template<> 
struct helper<char> { void operator() (char c) { /**/}}; 
template<typename T> 
struct helper<std::list<T>> { void operator() (const std::list<T>& l) { /**/}}; 

template<typename T> 
void Params2(const T& t) { 
    helper<T>{}(t); 
} 
0

Использование std::enable_if() , вы можете создавать шаблоны, которые будут смешивать примитивные данные и «списки» примитивных данных. Фокус в том, что все, что имеет тип const_iterator и метод begin(), который возвращает тип, конвертируемый в этот тип, будет рассматриваться как список, а все остальное будет перенаправлено на соответствующие перегрузки.

void foo(const int& t) { std::cout << "int: " << t << std::endl; } 
void foo(const double& t) { std::cout << "double: " << t << std::endl; } 

template<typename T, 
     typename std::enable_if< 
      std::is_convertible< 
       decltype(std::declval<const T&>().begin()), 
       typename T::const_iterator 
      >::value 
     >::type* = nullptr> 
void foo(const T& t) { 
    auto begin = t.begin(); 
    for(;begin != t.end(); ++begin) { 
     foo(*begin); 
    } 
} 

template<typename T, 
     typename... TArgs> 
void foo(const T& first, TArgs... args) { 
    foo(first); 
    foo(args...); 
} 

int main() { 
    std::list<int> asdf{3, 4, 5}; 
    std::vector<double> vec{7, 8, 9}; 
    foo(1, 2.0, asdf, 6, vec); 
} 

Выход:

INT: 1
двойные: 2
INT: 3
INT: 4
INT: 5
INT: 6
двойные: 7
двойной: 8
двойной: 9