Remi.b
Remi.b

Reputation: 18219

How to evaluate Primitive vs Class templates at compilation time?

When we do ...

template <typename T>
void foo(T x)
{
   if (is_fundamental<T>::value)
   {
       ...
   } else
   {
     ...
   }
}

I would think that the if statement (as well as is_fundamental<T>::value) is evaluated at run time, is that right?

If yes, is there a way to make this evaluation at compilation time? I would like to have something like...

template <primitive_typename T>
void foo(T x)
{
   ...
}


template <noPrimitive_typename T>
void foo(T x)
{
   ...
}

One solution would be to overload every possible primitive type but it is not really a satisfying solution as it requires duplicating the code for primitive type many times. Is there no way to refer to all primitives with a a single typename?

Upvotes: 0

Views: 185

Answers (2)

max66
max66

Reputation: 66210

What about tag dispatching?

template <typename T>
void fooHelper (T t, std::true_type const &)
 { /* true case */ }

template <typename T>
void fooHelper (T t, std::false_type const &)
 { /* false case */ }

template <typename T>
void foo (T t)
 { fooHelper(t, std::is_fundamental<T>{}); }

Upvotes: 1

Brian Bi
Brian Bi

Reputation: 119219

In C++17 the if constexpr statement evaluates the condition at compile time and discards the branch that isn't selected:

if constexpr(std::is_fundamental_v<T>) {
    // do something with x
} else {
    // do something else with x
}

An old-fashioned way is to use tag dispatch:

template <typename FundamentalType>
void foo_helper(FundamentalType x, std::true_type);

template <typename NonFundamentalType>
void foo_helper(NonFundamentalType x, std::false_type);

template <typename T>
void foo(T x) {
    foo_helper(x, std::is_fundamental<T>{});
}

You can also use a partially specialized helper struct, but it's more code.

Upvotes: 8

Related Questions