How Does std::enable_if work?

后端 未结 2 1723
旧巷少年郎
旧巷少年郎 2020-12-01 09:42

I just asked this question: std::numeric_limits as a Condition

I understand the usage where std::enable_if will define the return type of a method condi

相关标签:
2条回答
  • 2020-12-01 10:08

    As is mentioned in comment by 40two, understanding of Substitution Failure Is Not An Error is a prerequisite for understanding std::enable_if.

    std::enable_if is a specialized template defined as:

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

    The key here is in the fact that typedef T type is only defined when bool Cond is true.

    Now armed with that understanding of std::enable_if it's clear that void foo(const T &bar) { isInt(bar); } is defined by:

    template<typename T>
    typename std::enable_if<std::numeric_limits<T>::is_integer, void>::type foo(const T &bar) { isInt(bar); }
    

    As mentioned in firda's answer, the = 0 is a defaulting of the second template parameter. The reason for the defaulting in template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> is so that both options can be called with foo< int >( 1 );. If the std::enable_if template parameter was not defaulted, calling foo would require two template parameters, not just the int.


    General note, this answer is made clearer by explicitly typing out typename std::enable_if<std::numeric_limits<T>::is_integer, void>::type but void is the default second parameter to std::enable_if, and if you have c++14 enable_if_t is a defined type and should be used. So the return type should condense to: std::enable_if_t<std::numeric_limits<T>::is_integer>

    A special note for users of visual-studio prior to visual-studio-2013: Default template parameters aren't supported, so you'll only be able to use the enable_if on the function return: std::numeric_limits as a Condition

    0 讨论(0)
  • 2020-12-01 10:25
    template<typename T, std::enable_if<std::is_integral<T>::value, int>::type = 0>
    void foo(const T& bar) { isInt(); }
    

    this fails to compile if T is not integral (because enable_if<...>::type won't be defined). It is protection of the function foo.The assignment = 0 is there for default template parameter to hide it.

    Another possibility: (yes the typename is missing in original question)

    #include <type_traits>
    
    template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
    void foo(const T& bar) {}
    
    template<typename T>
    typename std::enable_if<std::is_integral<T>::value>::type
    bar(const T& foo) {}
    
    int main() {
        foo(1); bar(1);
        foo("bad"); bar("bad");
    }
    
    error: no matching function for call to ‘foo(const char [4])’
      foo("bad"); bar("bad");
               ^
    note: candidate is:
    note: template::value, int>::type  > void foo(const T&)
     void foo(const T& bar) {}
          ^
    note:   template argument deduction/substitution failed:
    error: no type named ‘type’ in ‘struct std::enable_if’
     template::value, int>::type = 0>
                                                                                           ^
    note: invalid template non-type parameter
    error: no matching function for call to ‘bar(const char [4])’
      foo("bad"); bar("bad");
                           ^
    
    0 讨论(0)
提交回复
热议问题