Manual distinction of types when given any type T
suggest changeWhen implementing SFINAE using std::enable_if, it is often useful to have access to helper templates that determines if a given type T matches a set of criteria.
To help us with that, the standard already provides two types analog to true and false which are std::true_type and std::false_type.
The following example show how to detect if a type T is a pointer or not, the is_pointer template mimic the behavior of the standard std::is_pointer helper:
template <typename T>
struct is_pointer_: std::false_type {};
template <typename T>
struct is_pointer_<T*>: std::true_type {};
template <typename T>
struct is_pointer: is_pointer_<typename std::remove_cv<T>::type> { }
There are three steps in the above code (sometimes you only need two):
- The first declaration of
is_pointer_is the default case, and inherits fromstd::false_type. The default case should always inherit fromstd::false_typesince it is analogous to a “falsecondition”. - The second declaration specialize the
is_pointer_template for pointerT*without caring about whatTis really. This version inherits fromstd::true_type. - The third declaration (the real one) simply remove any unnecessary information from
T(in this case we removeconstandvolatilequalifiers) and then fall backs to one of the two previous declarations.
Since is_pointer<T> is a class, to access its value you need to either:
- Use
::value, e.g.is_pointer<int>::value–valueis a static class member of typeboolinherited fromstd::true_typeorstd::false_type; - Construct an object of this type, e.g.
is_pointer<int>{}– This works becausestd::is_pointerinherits its default constructor fromstd::true_typeorstd::false_type(which haveconstexprconstructors) and bothstd::true_typeandstd::false_typehaveconstexprconversion operators tobool.
It is a good habit to provides “helper helper templates” that let you directly access the value:
template <typename T>
constexpr bool is_pointer_v = is_pointer<T>::value;
In C++17 and above, most helper templates already provide a _v version, e.g.:
template< class T > constexpr bool is_pointer_v = is_pointer<T>::value;
template< class T > constexpr bool is_reference_v = is_reference<T>::value;