std::enable_if
is a powerful template metaprogramming tool in C++ that allows for conditional compilation of function templates based on compile-time conditions. It is commonly used for SFINAE (Substitution Failure Is Not An Error) techniques and to enable or disable function overloads based on type traits.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
is_odd(T i) {
return i % 2 != 0;
}
int main() {
std::cout << "Is 5 odd? " << is_odd(5) << std::endl;
// std::cout << "Is 3.14 odd? " << is_odd(3.14) << std::endl; // This would cause a compile error
return 0;
}
is_odd
function template is only enabled for integral types.std::enable_if<std::is_integral<T>::value, bool>::type
is used as the return type.T
is not an integral type, the function will not be part of the overload set, causing a compile-time error if called with a non-integral type.#include <iostream>
#include <type_traits>
#include <string>
class MyClass {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
print(T value) {
std::cout << "Integral type: " << value << std::endl;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, void>::type
print(T value) {
std::cout << "Floating-point type: " << value << std::endl;
}
template <typename T>
typename std::enable_if<std::is_same<T, std::string>::value, void>::type
print(const T& value) {
std::cout << "String type: " << value << std::endl;
}
};
int main() {
MyClass obj;
obj.print(42);
obj.print(3.14);
obj.print(std::string("Hello"));
return 0;
}
std::enable_if
can be used to create function overloads based on type traits.print
function templates are defined, each enabled for a specific type category:#include <iostream>
#include <type_traits>
template <typename T, typename Enable = void>
struct TypeInfo {
static constexpr const char* name = "Unknown";
};
template <typename T>
struct TypeInfo<T, typename std::enable_if<std::is_integral<T>::value>::type> {
static constexpr const char* name = "Integer";
};
template <typename T>
struct TypeInfo<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
static constexpr const char* name = "Floating-point";
};
int main() {
std::cout << "int is: " << TypeInfo<int>::name << std::endl;
std::cout << "double is: " << TypeInfo<double>::name << std::endl;
std::cout << "char is: " << TypeInfo<char>::name << std::endl;
std::cout << "std::string is: " << TypeInfo<std::string>::name << std::endl;
return 0;
}
std::enable_if
can be used for template specialization.TypeInfo
is defined with a default "Unknown" type name.std::enable_if
:T
.std::enable_if
is a versatile tool in C++ template metaprogramming that allows for:
It helps in writing more expressive and type-safe code by enabling or disabling certain template instantiations based on compile-time conditions. This can lead to better error messages, improved code organization, and more efficient compile-time type checking.
When using std::enable_if
, it's important to consider:
- The readability of the code, as complex enable_if conditions can be hard to understand
- The potential for increased compile times due to more complex template instantiations
- The need for fallback implementations or appropriate error messages when no enabled overload is found
Overall, std::enable_if
is a powerful feature that, when used judiciously, can greatly enhance the flexibility and robustness of template-based C++ code.
[1] https://leimao.github.io/blog/CPP-Enable-If/ [2] https://stackoverflow.com/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function [3] https://learn.microsoft.com/en-us/cpp/standard-library/enable-if-class?view=msvc-170 [4] https://cplusplus.com/reference/type_traits/enable_if/ [5] https://www.codeproject.com/Articles/878913/enable-if