Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to use std::enable_if

Tags:

c++

c++11

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.

like image 795
Sam Avatar asked Aug 11 '19 11:08

Sam


People also ask

What is std :: Enable_if?

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.

What is Typename C++?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.


1 Answers

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.

like image 159
Igor R. Avatar answered Oct 27 '22 09:10

Igor R.