2015-05-20 18 views
15

Chciałbym wymusić typ szablonu variadic, aby był identyczny z wcześniejszego typu szablonu zestawu. W poniższym przykładzie chciałbym, aby T i U były tego samego typu.Wymuszenie szablonu variadic określonego typu

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

powiązanymi: [Metoda szablonu variadic do zaakceptowania danej liczby podwójnych?] (Http://stackoverflow.com/questions/30179181) – Ruslan

Odpowiedz

11

Możemy użyć SFINAE aby upewnić się, że wszystkie U typy są takie same jak T. Ważną rzeczą jest to, że U to nie tylko jeden typ, jaki sugerujesz, ale lista możliwych typów.

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 pochodzi z C++ 14. Jeśli to nie jest opcja dla Ciebie, po prostu użyj std::enable_if.

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

all_same może być wdrożony na kilka różnych sposobów. Oto metoda Lubię używając logicznych pakiety:

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

Bez wdrażanie all_same można również zmienić kod konstruktora następująco:

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 jest funkcja w STL <type_traits>

+0

kodowanie typu "int" ogranicza używanie tej funkcji, – Jagannath

+0

@Jagannath faktycznie i t może być czymkolwiek, np. void, ponieważ jest tylko do określenia, czy typ jest poprawny –

+0

@Jagannath kluczową rzeczą jest wywołanie rekurencyjnie konstruktora wewnętrznego konstruktora typu, dopóki nie otrzymamy tylko jednego parametru –

Powiązane problemy