FreeBSD Manual Pages
std::enable_if(3) C++ Standard Libary std::enable_if(3) NAME std::enable_if - std::enable_if Synopsis Defined in header <type_traits> template< bool B, class T = void > (since C++11) struct enable_if; If B is true, std::enable_if has a public member typedef type, equal to T; otherwise, there is no member typedef. This metafunction is a convenient way to leverage SFINAE prior to C++20's concepts, in particular for conditionally removing functions from the candi- date set based on type traits, allowing separate function overloads or specializations based on those different type traits. std::enable_if can be used in many forms, including: * as an additional function argument (not applicable to operator overloads) * as a return type (not applicable to constructors and destruc- tors) * as a class template or function template parameter The behavior of a program that adds specializations for enable_if is undefined. Member types Type Definition type either T or no such member, depending on the value of B Helper types template< bool B, class T = void > (since C++14) using enable_if_t = typename enable_if<B,T>::type; Possible implementation template<bool B, class T = void> struct enable_if {}; template<class T> struct enable_if<true, T> { typedef T type; }; Notes A common mistake is to declare two function templates that differ only in their default template arguments. This does not work because the declara- tions are treated as redeclarations of the same function template (default template arguments are not accounted for in function template equivalence). /* WRONG */ struct T { enum { int_t, float_t } type; template <typename Integer, typename = std::enable_if_t<std::is_integral<Inte- ger>::value> > T(Integer) : type(int_t) {} template <typename Floating, typename = std::enable_if_t<std::is_float- ing_point<Floating>::value> > T(Floating) : type(float_t) {} // error: treated as redefinition }; /* RIGHT */ struct T { enum { int_t, float_t } type; template <typename Integer, std::enable_if_t<std::is_integral<Integer>::value, bool> = true > T(Integer) : type(int_t) {} template <typename Floating, std::enable_if_t<std::is_floating_point<Float- ing>::value, bool> = true > T(Floating) : type(float_t) {} // OK }; Care should be taken when using enable_if in the type of a template non-type parameter of a namespace-scope function template. Some ABI specifi- cations like the Itanium ABI do not include the instantiation-dependent portions of non-type template parameters in the mangling, meaning that specializations of two dis- tinct function templates might end up with the same mangled name and be erroneously linked together. For example: // first translation unit struct X { enum { value1 = true, value2 = true }; }; template<class T, std::enable_if_t<T::value1, int> = 0> void func() {} // #1 template void func<X>(); // #2 // second translation unit struct X { enum { value1 = true, value2 = true }; }; template<class T, std::enable_if_t<T::value2, int> = 0> void func() {} // #3 template void func<X>(); //#4 The function templates #1 and #3 have different signatures and are distinct templates. Nonetheless, #2 and #4, despite being instantiations of different function templates, have the same mangled name in the Itanium C++ ABI (_Z4funcI1XLi0EEvv), meaning that the linker will erroneously con- sider them to be the same entity. Example // Run this code #include <type_traits> #include <new> #include <iostream> #include <string> namespace detail { void* voidify(const volatile void* ptr) noexcept { return const_cast<void*>(ptr); } } // #1, enabled via the return type template<class T> typename std::enable_if<std::is_trivially_default_con- structible<T>::value>::type construct(T*) { std::cout << "default constructing trivially default constructible T\n"; } // same as above template<class T> typename std::enable_if<!std::is_trivially_default_con- structible<T>::value>::type construct(T* p) { std::cout << "default constructing non-trivially default con- structible T\n"; ::new(detail::voidify(p)) T; } // #2 template<class T, class... Args> std::enable_if_t<std::is_constructible<T, Args&&...>::value> // Using helper type construct(T* p, Args&&... args) { std::cout << "constructing T with operation\n"; ::new(detail::voidify(p)) T(static_cast<Args&&>(args)...); } // #3, enabled via a parameter template<class T> void destroy( T*, typename std::enable_if< std::is_trivially_destructible<T>::value >::type* = 0 ){ std::cout << "destroying trivially destructible T\n"; } // #4, enabled via a non-type template parameter template<class T, typename std::enable_if< !std::is_trivially_destructible<T>{} && (std::is_class<T>{} || std::is_union<T>{}), bool>::type = true> void destroy(T* t) { std::cout << "destroying non-trivially destructible T\n"; t->~T(); } // #5, enabled via a type template parameter template<class T, typename = std::enable_if_t<std::is_array<T>::value> > void destroy(T* t) // note: function signature is unmodified { for(std::size_t i = 0; i < std::extent<T>::value; ++i) { destroy((*t)[i]); } } /* template<class T, typename = std::enable_if_t<std::is_void<T>::value> > void destroy(T* t){} // error: has the same signature with #5 */ // the partial specialization of A is enabled via a template parameter template<class T, class Enable = void> class A {}; // primary template template<class T> class A<T, typename std::enable_if<std::is_float- ing_point<T>::value>::type> { }; // specialization for floating point types int main() { std::aligned_union_t<0,int,std::string> u; construct(reinterpret_cast<int*>(&u)); destroy(reinterpret_cast<int*>(&u)); construct(reinterpret_cast<std::string*>(&u),"Hello"); destroy(reinterpret_cast<std::string*>(&u)); A<int>{}; // OK: matches the primary template A<double>{}; // OK: matches the partial specialization } Output: default constructing trivially default constructible T destroying trivially destructible T constructing T with operation destroying non-trivially destructible T See also void_t void variadic alias template (C++17) (alias template) * static_assert * SFINAE * Constraints and Concepts http://cppreference.com 2022.07.31 std::enable_if(3)
NAME | Synopsis | Member types | Helper types | Possible implementation | Notes | Example | Output: | See also
Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=std::enable_if&sektion=3&manpath=FreeBSD+Ports+15.0>
