GSP
Quick Navigator

Search Site

Unix VPS
A - Starter
B - Basic
C - Preferred
D - Commercial
MPS - Dedicated
Previous VPSs
* Sign Up! *

Support
Contact Us
Online Help
Handbooks
Domain Status
Man Pages

FAQ
Virtual Servers
Pricing
Billing
Technical

Network
Facilities
Connectivity
Topology Map

Miscellaneous
Server Agreement
Year 2038
Credits
 

USA Flag

 

 

Man Pages
std::enable_if(3) C++ Standard Libary std::enable_if(3)

std::enable_if - std::enable_if


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 candidate 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 destructors)
* as a class template or function template parameter


The behavior of a program that adds specializations for enable_if is undefined.


Type Definition
type either T or no such member, depending on the value of B


template< bool B, class T = void > (since C++14)
using enable_if_t = typename enable_if<B,T>::type;


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


template<class T>
struct enable_if<true, T> { typedef T type; };


A common mistake is to declare two function templates that differ only in their
default template arguments. This does not work because the declarations 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<Integer>::value>
>
T(Integer) : type(int_t) {}


template <typename Floating,
typename = std::enable_if_t<std::is_floating_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<Floating>::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 specifications like the
Itanium ABI do not include the instantiation-dependent portions of non-type template
parameters in the mangling, meaning that specializations of two distinct 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 consider them to be
the same entity.

// 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_constructible<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_constructible<T>::value>::type
construct(T* p)
{
std::cout << "default constructing non-trivially default constructible 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_floating_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
}


default constructing trivially default constructible T
destroying trivially destructible T
constructing T with operation
destroying non-trivially destructible T


void_t void variadic alias template
(C++17) (alias template)


* static_assert
* SFINAE
* Constraints and Concepts

2022.07.31 http://cppreference.com

Search for    or go to Top of page |  Section 3 |  Main Index

Powered by GSP Visit the GSP FreeBSD Man Page Interface.
Output converted with ManDoc.