Professional C__ - Marc Gregoire [362]
typename is_integral This uses is_integral to see if T is an integral type. Calling ::type will return the resulting integral_constant, which can be a true_type or a false_type. The process_helper() function needs an instance of true_type or false_type as second parameter, so that is the reason for the two empty brackets behind ::type. Note that the two overloaded process_helper() functions use nameless parameters of type true_type or false_type. They are nameless because they don’t use those parameters inside their function body. If you don’t like this syntax, you might as well write the following: void process_helper(const T& t, true_type tt) However, because tt will not be used in the body of the function, this will most likely trigger a warning from your compiler saying that tt is unused. Using Type Relations There are three type relations available: is_same, is_base_of and is_convertible. They all work similarly. This section gives an example of how to use is_same. The following example defines a same_helper() function template. It accepts two constant references and one Boolean value. The function prints the two values followed by a specific string depending on the value of the Boolean parameter. The same() function template uses the is_same type traits feature to figure out whether the two given arguments are of the same type or not and then calls the same_helper() function. It uses ::value because the same_helper() function requires a Boolean value true or false. Using the same() function template is very easy as is shown in the main() function: template void same_helper(const T1& t1, const T2& t2, bool b) { cout << "'" << t1 << "' and '" << t2 << "' are "; cout << (b ? "the same types." : "different types.") << endl; } template void same(const T1& t1, const T2& t2) { same_helper(t1, t2, is_same } int main() { same(1, 32); same(1, 3.01); same(3.01, string("Test")); } Code snippet from TypeTraits\is_same.cpp The output should be as follows: '1' and '32' are the same types. '1' and '3.01' are different types '3.01' and 'Test' are different types Using enable_if First, a little warning before continuing with enable_if. Using enable_if requires knowledge of a feature called Substitution Failure Is Not An Error (SFINAE), a complicated and obscure feature of C++. This section explains the basics of SFINAE with an example. The previous example with the same() and same_helper() function templates can be rewritten into one overloaded check_type() function template by using the enable_if type traits transformation as follows: template void check_type(const T1& t1, const T2& t2, typename enable_if { cout << "'" << t1 << "' and '" << t2 << "' "; cout << "are the same types." << endl; } template void check_type(const T1& t1, const T2& t2, typename enable_if::value>::type* p = nullptr) { cout << "'" << t1 << "' and '" << t2 << "' "; cout << "are different types." << endl; } int main() { check_type(1, 32); check_type(1, 3.01); check_type(3.01, string("Test")); } Code snippet from TypeTraits\enable_if.cpp The output will be: '1' and '32' are the same types. '1' and '3.01' are different types. '3.01' and 'Test' are different types. This example defines one function called check_type(), which is overloaded on its third parameter. The third parameter for the first overload looks as follows: typename enable_if It first uses is_same to check whether the two types are the same or not and gets the value of that result with ::value. This value is given to enable_if, and ::type is used to get the resulting type. When the argument to enable_if is true,