2013-03-14 8 views
35

Czy istnieje standardowy sposób dla mnie, aby wybrać typ na czasu kompilacji na niepodpisany indeks w C++ 11?Jak przełączać/wybierać typy podczas kompilacji?

Na przykład coś takiego:

using type_0 = static_switch<0,T,U>; // yields type T 
using type_1 = static_switch<1,T,U>; // yields type U 

Jeśli istnieje wersja o zmiennej liczbie argumentów, szablon, byłoby bardzo przydatne.

Odpowiedz

42

To powinno działać:

template<std::size_t N, typename... T> 
using static_switch = typename std::tuple_element<N, std::tuple<T...> >::type; 

inną metodą:

template<std::size_t N, typename T, typename... Ts> 
struct static_switch { 
    using type = typename static_switch<N - 1, Ts...>::type; 
}; 
template<typename T, typename... Ts> 
struct static_switch<0, T, Ts...> { 
    using type = T; 
}; 
+1

+1 Znakomita odpowiedź . Zawsze interesują mnie nowe sposoby używania szablonów variadic. Dzięki za kolejną. – WhozCraig

+0

+1 Nie wiedziałem, że możesz mieć szablonowe "używanie". –

+1

@AlexChamberlain nie wszystkie kompilatory go obsługują (tak, to jest ich najnowsza wersja) –

10

Można chyba użyć boost::mpl::vector przechowywać swoje typy i używać boost::mpl::at<v,n>::type uzyskać typ z z indeksu.

template<std::size_t N, typename... T> 
using static_switch = typename boost::mpl::at<boost::mpl::vector<T...>, N>::type; 
8

Jak o

template<size_t N, typename T, typename U> 
struct static_switch {}; 

template<typename T, typename U> 
struct static_switch<0, T, U>{typedef T type;}; 

template<typename T, typename U> 
struct static_switch<1, T, U>{typedef U type;}; 

by go użyć w następujący sposób:

using type_0 = static_switch<0,T,U>::type; // yields type T 
using type_1 = static_switch<1,T,U>::type; // yields type U 

ta jest bardziej lub mniej wdrożone dla Ciebie w std::conditional.

+8

Uwaga: 'std :: conditional' jest świetny, jeśli istnieją tylko 2 alternatywy. Ponieważ PO mówi o indeksie, może być ich więcej. –

1

Z C++ 17 można również przejść w inny sposób. Zamiast obliczania typ wyraźnie można użyć constexpr if i robić różne rzeczy (w tym powrocie różne rodzaje) bezpośrednio:

template<size_t N> 
decltype(auto) foo(){ 
    if constexpr(N%2==0){ 
     return std::string("Hello I'm even"); 
    }else{ 
     return std::pair(
      std::vector<char>{'O','d','d',' ','v','a','l','u','e'}, 
      [](){ return N; });   
    } 
} 

foo<0>()   // "Hello I'm even" 
foo<21>().second() // 21 

Można również użyć tego, aby właśnie rodzaj:

using type_0 = decltype(foo<0>()); 
using type_1 = decltype(foo<1>());