23

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;
};
porgarmingduod
  • 7,668
  • 10
  • 50
  • 83

3 Answers3

26

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;
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    `template struct remove_pointer { typedef U type; };` ? –  Nov 23 '11 at 13:52
  • 4
    Every time I learn new C++ syntax, the readability of all future code I write suffer... – porgarmingduod Nov 23 '11 at 14:09
  • 2
    @porgarmingduod: On the contrary! Look at my last line in the updated post: One line, and it's totally self-descriptive. If you use the right tools and building blocks, your code will actually become *more* readable and less verbose. You replace opaque syntax nonsense with self-descriptive one-liners. – Kerrek SB Nov 23 '11 at 14:14
  • @KerrekSB: You are right, I was joking. I'm already using std::conditional to greatly simplify a hairy class; making it more generic and useful with less code. – porgarmingduod Nov 23 '11 at 14:29
10

@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.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 17
    This is also known as `std::conditional` :-) – Kerrek SB Nov 23 '11 at 13:48
  • @KerrekSB: std::conditional was exactly what I needed. Though your answer is more general so I'll pick that for posterity. – porgarmingduod Nov 23 '11 at 14:08
  • 2
    @porgarmingduod: The golden rule is that you should be *aware* of how to use template specialization to make compile-time decisions, and *then* you look at the `` library and see all the wonderful tools that are already made for you to use :-) – Kerrek SB Nov 23 '11 at 14:10
0

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]

No-Bugs Hare
  • 1,557
  • 14
  • 15