porgarmingduod
porgarmingduod

Reputation: 7888

C++ templates: Select different type based on value of template parameter

How do I accomplish the following in C++, and what is doing such things called?

template <bool S>
class NuclearPowerplantControllerFactoryProviderFactory {
  // if S == true
  typedef int data_t;
  // if S == false
  typedef unsigned int data_t;
};

Upvotes: 26

Views: 23819

Answers (3)

No-Bugs Hare
No-Bugs Hare

Reputation: 1638

Since C++14, it can and should be done using std::conditional<> , see https://en.cppreference.com/w/cpp/types/conditional

[under the hood, it is the same as solution suggested by @Nawaz but standard solutions are always preferable whenever available]

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477600

By specialization:

template <bool> class Foo;

template <> class Foo<true>
{
  typedef int data_t;
};

template <> class Foo<false>
{
  typedef unsigned int data_t;
};

You can choose to make one of the two cases the primary template and the other one the specialization, but I prefer this more symmetric version, given that bool can only have two values.


If this is the first time you see this, you might also like to think about partial specialization:

template <typename T> struct remove_pointer     { typedef T type; };
template <typename U> struct remove_pointer<U*> { typedef U type; };


As @Nawaz says, the easiest way is probably to #include <type_traits> and say:

typedef typename std::conditional<S, int, unsigned int>::type data_t;

Upvotes: 28

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361772

@Kerrek has answered the question sufficiently, but that can be more generic as follows:

template<bool b, typename T, typename U>
struct select
{
    typedef T type;
};
template<typename T, typename U>
struct select<false, T, U>
{
    typedef U type;
};

And use as:

template <bool S>
class NuclearPowerplantControllerFactoryProviderFactory 
{
  typedef typename select<S, int, unsigned int>::type data_t;
  //use data_t as data type
};

If S is true, the first type argument in select will be selected, or else second type argument will be selected. It is generic because you specify both types in select<>, and based on the value of the boolean, select<b,T,U>::type returns either first type, or second type.

Upvotes: 11

Related Questions