Question

I've seen a template written this way:

    template<typename T, bool = is_integral<T>::value, bool = is_floating_point<T>::value>
    struct helper {};

    template<typename T>
    struct helper<T, true, false>
    {
        typedef TypeAppropriateForThisSpecialization type;
    };

and then used

typename helper<T>::type t;

What does it mean? Does it mean that there is a specialization for the true-false combination of template type params that, if they're ommited, get evaluated by is_integral and is_floating_point ?

Is this the same? (this is a variable declaration/definition):

typename helper<T, true, false>::type t;

typename helper<T, is_integral<T>::value, is_floating_point<T>::value>::type t;
Was it helpful?

Solution

What does it mean? Does it mean that there is a specialization for the true-false combination of template type params that, if they're ommited, get evaluated by is_integral and is_floating_point ?

The idea behind the code is to either select the specialization where type is defined, or the other (where type is not defined).

If the user of the helper does not specify the default template parameters. The specialization shall be selected if type T is an integral and not a floating point value, else the non-specialized template shall be selected.

Is this the same? (this is a variable declaration/definition):

typename helper<T, true, false>::type t;
typename helper<T, is_integral<T>::value, is_floating_point<T>::value>::type t;

The above mentioned type definitions would have the same result if T is indeed integral and not a floating point, else they would have a different result (in which case ::type may be invalid).

This type of code might be used in SFINAE. See more c++ idioms - enable if as example. You can also look at boost::enable_if. It would be good if you can give us an example of usage.

This (idiom) would be used to select a different function in an overload set based on an attribute of T, and not the type only (see example below for similar usage of enable_if).

#include <type_traits>
#include <iostream>
#include <string>


template <class T>
typename std::enable_if<std::is_floating_point<T>::value>::type foo( T )
{
  std::cout << "T is a float" << std::endl;
}

template <class T>
typename std::enable_if<
  std::is_integral<T>::value &&
  std::is_unsigned<T>::value>::type foo( T )
{
  std::cout << "T is integral and unsigned" << std::endl;
}

template <class T>
typename std::enable_if<
 std::is_integral<T>::value &&
 std::is_signed<T>::value>::type foo( T )
{
  std::cout << "T is integral and signed" << std::endl;
}

template <class T>
typename std::enable_if<
 !(std::is_integral<T>::value || std::is_floating_point<T>::value)>::type
 foo( T )
{
  std::cout << "T is neiter integral nor float" << std::endl;
}

int main()
{
  foo( 10u );
  foo( 10 );
  foo( 10.2 );
  foo( std::string() );
  return 0;
}

OTHER TIPS

typename helper<T>::type t;
typename helper<T, is_integral<T>::value, is_floating_point<T>::value>::type t;

Are the same.

and helper<T, true, false> is specialized (so when T is a integral but not a floating point when used in helper<T>).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top