Movatterモバイル変換


[0]ホーム

URL:


cppreference.com
Namespaces
Variants
    Actions

      std::enable_if

      From cppreference.com
      <cpp‎ |types
       
       
      Metaprogramming library
      Type traits
      Type categories
      (C++11)
      (C++11)(DR*)
      (C++11)
      (C++11)
      (C++11)
      (C++11)
      (C++11)
      (C++11) 
      Type properties
      (C++11)
      (C++11)
      (C++14)
      (C++11)(deprecated in C++26)
      (C++11)(until C++20*)
      (C++11)(deprecated in C++20)
      (C++11)
      Type trait constants
      Metafunctions
      (C++17)
      Supported operations
      Relationships and property queries
      Type modifications
      Type transformations
      (C++11)(deprecated in C++23)
      (C++11)(deprecated in C++23)
      (C++11)
      (C++11)(until C++20*)(C++17)

      enable_if
      (C++11)
      (C++17)
      Compile-time rational arithmetic
      Compile-time integer sequences
       
      Defined in header<type_traits>
      template<bool B,class T=void>
      struct enable_if;
      (since C++11)

      IfB istrue,std::enable_if has a public member typedeftype, equal toT; otherwise, there is no member typedef.

      This metafunction is a convenient way to leverageSFINAE prior to C++20'sconcepts, in particular for conditionally removing functions from thecandidate 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 most operator overloads),
      • as a return type (not applicable to constructors and destructors),
      • as a class template or function template parameter.

      If the program adds specializations forstd::enable_if, the behavior is undefined.

      Contents

      [edit]Member types

      Type Definition
      type eitherT or no such member, depending on the value ofB

      [edit]Helper types

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

      [edit]Possible implementation

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

      [edit]Notes

      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 infunction 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 usingenable_if in the type of a constant template parameter of a namespace-scope function template. Some ABI specifications like the Itanium ABI do not include the instantiation-dependent portions of constant 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 templatevoid 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 templatevoid 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 namein the Itanium C++ ABI (_Z4funcI1XLi0EEvv), meaning that the linker will erroneously consider them to be the same entity.

      [edit]Example

      Run this code
      #include <iostream>#include <new>#include <string>#include <type_traits> namespace detail{void* voidify(constvolatilevoid* ptr)noexcept{returnconst_cast<void*>(ptr);}} // #1, enabled via the return typetemplate<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 abovetemplate<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;} // #2template<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 parametertemplate<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 constant template parametertemplate<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 parametertemplate<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 parametertemplate<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(){union{int i;char s[sizeof(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 Tdestroying trivially destructible Tconstructing T with operationdestroying non-trivially destructible T

      [edit]See also

      (C++17)
      void variadic alias template
      (alias template)[edit]
      Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/types/enable_if&oldid=182715"

      [8]ページ先頭

      ©2009-2025 Movatter.jp