again about C++ SFINAE in enable_if_t

时间:2018-12-03 13:02:32

标签: c++ templates template-meta-programming sfinae

I'm trying to figure out why SFINAE doesn't work with a direct template argument initialization?

It works in this form, when I declare another template parameter, here:

#include <iostream>

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

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

template <bool B, class T>
using enable_if_t = typename enable_if<B,T>::type;

template< typename T >
struct Y {

public:
    template< typename U = T >
    enable_if_t<true, U>
    foo() {
        return 111;
    }

    template< typename U = T >
    enable_if_t<false, U>
    foo() {
        return 222;
    }
};

int main() {
    Y< double > y;
    std::cout << y.foo() << std::endl;
}

(prints out 111)

but if I refactor to this syntax, the compiler gives an error:

#include <iostream>

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

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

template <bool B, class T>
using enable_if_t = typename enable_if<B,T>::type;

template< typename T >
struct Y {    
    template< typename U = enable_if_t<true, T> >
    U
    foo() {
        return 11;
    }

    template< typename U = enable_if_t<false, T> >
    U
    foo() {
        return 12;
    }
};

int main() {
    Y< double > y;
    std::cout << y.foo() << std::endl;
}

"Class member cannot be redeclared" I assume the second instance formed invalid and should be excluded by SFINAE?

And why can't I declare foo()'s like this:

enable_if_t<true, T> foo() { return 11; } 
enable_if_t<false, T> foo() { return 12; } 

based just on the class template's T parameter? the second enable_if_t should not be valid and the instance of foo() should be discarded, right?

1 个答案:

答案 0 :(得分:1)

In the second case, you declare two class methods:

template<typename U> U foo();

You can't have two template class methods with the same signature and name just like you can't declare two non-template class methods with the same signature and name:

int bar();

and

int bar();

Your two template class methods have different template parameters defaults, but that is immaterial. Template parameter defaults are not considered to be a part of the signature. SFINAE does not come into play here. SFINAE is something that happens when template substitution occurs, the "S" part, not declaration.