简体   繁体   中英

Correct way to use std::enable_if

What are the differences between these classes? Precisely these methods with enable_if.

/// Alias of std::enable_if...
template <bool B, typename T = void>
using Enable_if = typename std::enable_if<B, T>::type;

Template<typename T, std::size_t N>
class A {
   ...
    template <std::size_t NN = N,
          typename = Enable_if<NN == 2>>
    Some_Return_Type
    method(param1, param2)
    {}

    template <std::size_t NN = N,
              typename = Enable_if<NN == 1>>
    Some_Return_Type
    method(param1)
    {}


};


Template<typename T, std::size_t N>
class B {
   ...
    Enable_if<N == 2, Some_Return_Type>
    method(param1, param2)
    {}

    Enable_if<N == 1, Some_Return_Type>
    method(param1)
    {}
};

What is the correct way to use enable_if in the case I have:

  • At least 2 methods that differs only in their arguments and they have the same name but just one of them must be "active" (if N == 1 one of them, if N == 2 the other).
  • Only one method that will be active if N == 0 and not active in other cases.

I would like to get something like:

Obj<int, 2> obj2;
Obj<int, 0> obj0;
Obj<int, 1> obj1;

if I write in the IDE obj0. it shows only methods of N == 0 ; obj1. only N == 1 , ... .

Thanks.

Note that enable_if is aimed to trigger SFINAE: if a template parameter substitution fails in its immediate context, it is not a compilation error.

This is exaclty what happens in class A : when the user calls a.method(...) , the compiler attempts to instantiate member function template method , subsituting NN parameter with a constant, which might fail.

However, in case of B::method the "bad" substitution occurs during class template B instantiation, when the compiler substitues N . The failure occurs far from the parameter's immediate context, which is in this case template<typename T, std::size_t N> class B .

That's why in the second case you will get a compilation error, rather than SFINAE.

So, to enable/disable member functions depending on the class template parameter, use the first approach, combining conditions as you wish. For instance:

template <typename T, std::size_t N>
class A {
    template <std::size_t NN = N, typename = std::enable_if_t<NN == 2 || NN == 0>>
    void method(int, int)
    {}

    template <std::size_t NN = N, typename = std::enable_if_t<NN == 1 || NN == 0>>
    void method(int)
    {}
};

UPDATE : How enable_if works. Roughly, one can implement it like this:

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

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

Note that if the first argument is false , enable_if doesn't have inner type , so enable_if<false, int>::type would be ill-formed. That's what triggers SFINAE.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM