2015-05-20 2 views
15

Я бы хотел, чтобы тип вариационного шаблона был идентичен типу более раннего заданного шаблона. В приведенном ниже примере я хотел бы, чтобы T и U были одного типа.Использовать вариационный шаблон определенного типа

code on ideone.com

#include <iostream> 
#include <string> 

template<class T> 
struct Foo { 

    Foo(T val) { 
     std::cout << "Called single argument ctor" << std::endl; 
     // [...]  
    }  

    // How to enforce U to be the same type as T? 
    template<class... U> 
    Foo(T first, U... vals) { 
     std::cout << "Called multiple argument ctor" << std::endl; 
     // [...] 
    } 

}; 

int main() { 

    // Should work as expected. 
    Foo<int> single(1); 

    // Should work as expected. 
    Foo<int> multiple(1, 2, 3, 4, 5); 

    // Should't work (but works right now). The strings are not integers. 
    Foo<int> mixedtype(1, "a", "b", "c"); 

    // Also shouldn't work. (doesn't work right now, so that is good) 
    Foo<int> alsomixedtype(1, 1, "b", "c"); 
} 
+0

связанныхсоздоровья [Метод вариационного шаблона для принятия заданного количества парных чисел?] (Http://stackoverflow.com/questions/30179181) – Ruslan

ответ

11

Мы можем использовать SFINAE, чтобы гарантировать, что все типы U такие же, как T. Важно отметить, что U - это не только один тип, как вы подразумеваете, но список возможных разнородных типов.

template<class... U, std::enable_if_t<all_same<T, U...>::value>* = nullptr> 
Foo(T first, U... vals) { 
    std::cout << "Called multiple argument ctor" << std::endl; 
    // [...] 
} 

std::enable_if_t от C++ 14. Если это не вариант для вас, просто используйте std::enable_if.

typename std::enable_if<all_same<T, U...>::value>::type* = nullptr> 

all_same может быть реализован в кучу разных способов. Вот метод, который я люблю использовать логические пакеты:

namespace detail 
{ 
    template<bool...> struct bool_pack; 
    template<bool... bs> 
    //if any are false, they'll be shifted in the second version, so types won't match 
    using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>; 
} 
template <typename... Ts> 
using all_true = detail::all_true<Ts::value...>; 

template <typename T, typename... Ts> 
using all_same = all_true<std::is_same<T,Ts>...>; 
0

Без внедрения all_same вы можете также изменить код конструктора следующим образом:

template<class F, typename = typename enable_if<is_same<F, T>::value>::type, class... U> 
    Foo(F first, U... vals): Foo(vals...) { 
    std::cout << "Called multiple argument ctor" << std::endl; 
    // [...] 
} 

is_same функция в STL <type_traits>

+0

жесткое кодирование типа 'int' ограничивает использование этой функции, – Jagannath

+0

@Jagannath фактически i t может быть любым, например, void, так как это только для того, чтобы определить, действительно ли тип –

+0

@Jagannath. Главное - мы вызываем конструктор конструктора внутреннего типа рекурсивно, пока не получим только один параметр –