Krzysztof
Krzysztof

Reputation: 779

std::enable_if for two different methods implementation (4 different cases)

I need to implement two different methods for const and non-const types. I have manage to write working code but I do not understand why some of its flavors are OK and some of them are not.

Here is simplified example and I would like to know why #1 works but #2 is not, and same regarding #3 vs #4:

#include <iostream>
#include <vector>

template <typename T>
class X {
public:
    // #1 - works
    template<typename B = T, typename std::enable_if<std::is_const<B>::value, int>::type = 0>
    void foo() {std::cout << "CONST" << std::endl;}
    template<typename B = T, typename std::enable_if<std::is_const<B>::value == false, int>::type = 0>
    void foo() {std::cout << "NON-CONST" << std::endl;}

    // #2 - does not work "no type named 'type' in 'std::__1::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration"
//    template<typename std::enable_if<std::is_const<T>::value, int>::type = 0>
//    void foo() {std::cout << "CONST" << std::endl;}
//    template<typename std::enable_if<std::is_const<T>::value == false, int>::type = 0>
//    void foo() {std::cout << "NON-CONST" << std::endl;}

    // #3 - works
//    template<typename B = T, typename = typename std::enable_if<std::is_const<B>::value>::type>
//    void foo() {std::cout << "CONST" << std::endl;}
//    template<typename B = T, typename std::enable_if<std::is_const<B>::value == false>::type * = nullptr>
//    void foo() {std::cout << "NON-CONST" << std::endl;}

    // # 4 - does not work - "class member cannot be redeclared"
//    template<typename B = T, typename = typename std::enable_if<std::is_const<B>::value>::type>
//    void foo() {std::cout << "CONST" << std::endl;}
//    template<typename B = T, typename = typename std::enable_if<std::is_const<B>::value == false>::type>
//    void foo() {std::cout << "NON-CONST" << std::endl;}
};

int main() {
    X<int> v;
    X<const int> vConst;

    v.foo();
    vConst.foo();

    return 0;
}

Even if there is a better approach to solve my problem I would really like to understand why enable_if works like it (not) works in presented examples.

Upvotes: 3

Views: 1530

Answers (1)

Jarod42
Jarod42

Reputation: 218323

#2 doesn't works as your have hard failure as T is fixed by the class.

so you really have

template<typename std::enable_if<true, int>::type = 0>  // -> template<int = 0>  void foo();
void foo();

template<typename std::enable_if<false, int>::type = 0> // Hard error failure
void foo();

For #4, default template value/type are not part of the signature, so once those removed, you have

template <typename B, typename> void foo() {std::cout << "CONST" << std::endl;}
template <typename B, typename> void foo() {std::cout << "NON-CONST" << std::endl;}

Same method with several definitions: you break ODR.

For #3, it would be:

template<typename B, typename>
void foo();

template<typename B, typename std::enable_if<std::is_const<B>::value == false>::type *>
void foo();

which are different.

Upvotes: 7

Related Questions