kfmfe04
kfmfe04

Reputation: 15327

How do I switch/select types during compile-time?

Is there a standard way for me to select a type at compile-time on an unsigned index in c++11?

For example, something like:

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

If there is a variadic-template version, it would be very useful.

Upvotes: 39

Views: 8151

Answers (4)

Morwenn
Morwenn

Reputation: 22552

You could probably use a boost::mpl::vector to store your types and use boost::mpl::at<v, n>::type to get a type with from the index.

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

Upvotes: 10

Alex Chamberlain
Alex Chamberlain

Reputation: 4207

How about

 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;};

You would use it as follows:

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

This is more or less implemented for you in std::conditional.

Upvotes: 9

Johan Lundberg
Johan Lundberg

Reputation: 27028

With C++17 you can also go about this another way. Instead of calculating the type explicitly you can use constexpr if and do different things (including returning different types) directly:

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

You can also use this to get just the type:

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

Upvotes: 2

Pubby
Pubby

Reputation: 53047

This should work:

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

Another method:

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;
};

Upvotes: 51

Related Questions