std::enable_if and boost::enable_if,boost::enable_if_c. differences and relations between

Keywords: C C++ boost

The standard library and the three enablers of boost_ If series of functions can help us overload template functions.

Overloading of general functions

Let's take a look at an example of general function overloading:

#include <iostream>

void print(int i)
{
  std::cout << "Integral: " << i << std::endl;
}

void print(double f)
{
  std::cout << "Floating point: " << f << std::endl;
}

int main()
{
  print(42);
  print(3.14);
 
}

above code It is an overload of a general function. The program will match according to the parameter type of the function and execute the corresponding function.
However, if the print above is a class template function, can it implement similar functions, such as:

template <typename T>
void print(T f)
{
  std::cout << "Floating point: " << f << std::endl;
}

When type T is double, call the function corresponding to the above parameter 3.14. When type T is int, call the function corresponding to the above parameter 42. Obviously, if the above parameters are uniformly replaced with T, take int and double as examples:

template <typename T>
void print(T f)
{
  std::cout << "Floating point: " << f << std::endl;
}


template <typename T>
void print(T f)
{
    std::cout << "Integral: " << i << std::endl;
}

The compiler will prompt: redefinition of 'template void print(T)
Then, is there a way to generate code of the corresponding type only when the template parameter is a certain type. std::enable_if and boost are designed to help implement similar functions.

std::enable_ Role of if

First look at std::enable_if definition:

std::enable_if itself is a template function with two template parameters. The first is a bool type non type parameter, and the second is the type parameter T. when the bool value is true, std::enable_if defines a typedef type of public type, which is the same as T. one possible implementation is:

template<bool B, class T = void>
struct enable_if {};
 
template<class T>
struct enable_if<true, T> { typedef T type; };

In this way, if we have a template function to judge a certain type, we can easily implement the function we want.
C++11 introduces a large number of judgment types template function:

Using the above type traits, the code is rewritten as follows, which can be easily compiled:

#include <type_traits>
#include <iostream>

template <typename T>
void print(typename std::enable_if<std::is_integral<T>::value, T>::type i)
{
  std::cout << "Integral: " << i << '\n';
}

template <typename T>
void print(typename std::enable_if<std::is_floating_point<T>::value, T>::type f)
{
  std::cout << "Floating point: " << f << '\n';
}



int main()
{
  print<short>(1);
  print<long>(2);
  print<double>(3.14);
}

std::enable_if and boost::enable_if difference

View boost::enable_if statement:

template <class Cond, class T = void> struct enable_if;

Find that the first parameter is type, and then check boost::enable_if_c declaration and definition of:

template <bool B, class T = void>
struct enable_if_c {
    typedef T type;
};

template <class T>
struct enable_if_c<false, T> {};

template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};

boost::enable_if_c and std::enable_if is equivalent
Change the above code to boost version:

#include <boost/utility/enable_if.hpp>
#include <type_traits>
#include <iostream>

template <typename T>
void print(typename boost::enable_if<std::is_integral<T>, T>::type i)
{
  std::cout << "Integral: " << i << '\n';
}

template <typename T>
void print(typename boost::enable_if<std::is_floating_point<T>, T>::type f)
{
  std::cout << "Floating point: " << f << '\n';
}

int main()
{
  print<short>(1);
  print<long>(2);
  print<double>(3.14);
}

Or boost:: Enable_ if_ Version C:

#include <boost/utility/enable_if.hpp>
#include <type_traits>
#include <iostream>

template <typename T>
void print(typename boost::enable_if_c<std::is_integral<T>::value, T>::type i)
{
  std::cout << "Integral: " << i << '\n';
}

template <typename T>
void print(typename boost::enable_if_c<std::is_floating_point<T>::value, T>::type f)
{
  std::cout << "Floating point: " << f << '\n';
}

int main()
{
  print<short>(1);
  print<long>(2);
  print<double>(3.14);
}

So far, std::enable_if and boost::enable_if,boost::enable_ if_ The difference and connection of C is very clear.

Posted by romeo on Fri, 29 Oct 2021 09:25:57 -0700