C++ Template Specialization Using Enable If
Introduction
In C++ metaprogramming, std::enable_if
is an important function to enable certain types for template specialization via some predicates known at the compile time. Using types that are not enabled by std::enable_if
for template specialization will result in compile-time error.
In this blog post, I would like to discuss how to understand C++ std::enable_if
with an emphasis on its application in template parameters.
Non-Type and Type Template Parameters
To understand std::enable_if
, it is necessary to understand the non-type and type template parameters. Let’s get ourselves familiar with them by looking at two examples.
Non-Type Template Parameters
Please pay special attention to the class C
as this usage is often used with std::enable_if
.
1 | template <int N> |
Type Template Parameters
Please pay special attention to the class C
as this usage is often used with std::enable_if
.
1 | template <typename T> |
Template Specialization Using Enable If
std::enable_if
In C++, the class signature of std::enable_if
is as follows.
1 | template< bool B, class T = void > |
If B
is true, std::enable_if
has a public member typedef type
, equal to T
; otherwise, there is no member typedef.
std::enable_if
could be implemented as follows.
1 | template<bool B, class T = void> |
This means, whenever the implementation tries to access enable_if<B,T>::type
when B = false
, the compiler will raise compilation error, as the object member type
is not defined.
Since C++14, there is an additional helper shortcut std::enable_if_t
defined in the C++ standard library.
1 | template< bool B, class T = void > |
Enable Template Specialization Via Template Parameters
std::enable_if
or std::enable_if_t
could be used for restricting or enabling the types used for template specialization via template parameters. Any undesired types used for template specialization will be prevented by compiler.
Let’s check an example of enabling only one type or types for a template function. Here we enabled integer types for the function foo
and bar
using the predicate std::is_integral<T>::value
.
1 |
|
Notice that in this case we used the type template parameter compile-time checking for the function foo
and used the non-type template parameter compile-time checking for the function bar
.
When it comes to enabling multiple types for a template function, the type template parameter compile-time checking will be prevented by compiler as the declarations are treated as redeclarations of the same function template.
Here we enabled both integer types and floating point types for the function bar
using the predicate std::is_integral<T>::value
and std::is_floating_point<T>::value
, respectively.
1 |
|
The std::is_integral<T>::value
and std::is_floating_point<T>::value
are mutually exclusive and only one can be true
at compile time for one specialization.
As we have discussed previously, the program below is equivalent as the program above and it could be compiled with C++11 standard.
1 |
|
To understand std::enable_if
, for example, when std::is_integral<T>::value
is evaluated to be true
at compile time, std::enable_if_t<std::is_integral<T>::value, bool> = true
is equivalent std::enable_if_t<true, bool> = true
and is equivalent as typename std::enable_if<true, bool>::type = true
and is equivalent as typename bool = true
. The remaining typename
is probably an indicator and will be removed during preprocessing. So ultimately what compiler will see is bool = true
which is exactly the same as the class C
scenario in the non-type template parameters.
The same analysis could be performed on typename = std::enable_if_t<std::is_integral<T>::value, float>
as well to help the understanding.
Enable Template Specialization Via Others
std::enable_if
or std::enable_if_t
could be used for restricting or enabling the types used for template specialization via return type or function parameters. Understanding those is almost equivalent as understand enabling template specialization via template parameters, and I am not going to elaborate it here.
References
C++ Template Specialization Using Enable If