4
votes

(this question is not related to C++11/C++14: the examples are compiled using C++03)

enable_bool<T> has a member ::type only when T is bool

template <class T>
struct enable_bool
{};

template <>
struct enable_bool< bool >
{ typedef bool type; };

In the next snippet, the partial specialization is correct (see gcc.godbolt.org)

template <class T, class U, class Enable = T>
struct Foo
{
    static int bar() { return 0; }
};

template <class T, class U>
struct Foo< T, U, typename enable_bool<T>::type >
{
    static int bar() { return 1; }
};

int main()
{
    return Foo <int, bool>::bar();
}

As enable_bool<T>::type already corresponds to T (when T is bool)
we are tempted to factorize parameters T and Enable.
But compiler complains (see gcc.godbolt.org)

template <class T, class U>
struct Foo
{
    static int bar() { return 0; }
};

template <class T, class U> //ERROR non-deducible template parameter 'T'
struct Foo< typename enable_bool<T>::type, U >
{
    static int bar() { return 1; }
};

Why compiler cannot deduce template parameter T in this above partial specialization?

1
Dupe. tl;dr: yes, it's "specified in the C++ standard" in that it's a fundamental fact of how std::enable_if actually works. No, it won't "evolve" in C++17.Lightness Races in Orbit
Hi @LightnessRacesinOrbit. Thanks for your comment but question std::enable_if to conditionally compile a member function is not the same. In his answer, Johannes says "std::enable_if<>::type accesses a non-existing type, so that declaration is ill-formed". This is maybe the answer of my question. I wonder about the C++ Standard/Compiler reason to do not allow one single parameter for SFINAE (using std::enable_if or not). Please reopen my question. CheersoHo
It is my way of informing you that this requirement is due to how std::enable_if works. Therefore, to answer the question, you should read how std::enable_if works; certainly there is little to gain in our repeating all of that here. I did actually read the answers there (albeit briefly), and confirmed that they make reference to this particular requirement, within the broader scope and context of the feature in question.Lightness Races in Orbit
However, if you'd like to come back in a couple of days having studied that post, with specific queries that relate to the information therein, I'd be happy to take another look.Lightness Races in Orbit
Hi @LightnessRacesinOrbit. I have read questions/answers and std::enable_if documentation. But it is not obvious where the answer is. (Please give me the answer). I think it will not help SO users to be redirected to the other question (because the answer of my question is not blinking there). I have fully rewritten my question since first post. My question is not related to C++11 neither to std::enable_if. While rewriting/testing the code I got a light. I think the answer is because compiler needs to know where is the parameter int. If you reopen the question I can provide an answer.oHo

1 Answers

2
votes

Finally the question was not even related to SFINAE!

Consider this very simple snippet without SFINAE:
enable<T>::type is always same as T whatever the provided T type.

template <class T>
struct enable
{ typedef T type; };       // Enable always

template <class U, class V>
struct Foo
{
    static int bar() { return 0; }
};

template <class X, class Y> //ERROR non-deducible parameter 'X'
struct Foo< typename enable<X>::type, Y >
{
    static int bar() { return 1; }
};

int main()
{
    return Foo<int, bool>::bar();
}

When compiler tries to match Foo<int, bool> with Foo<typename enable<X>::type,Y>

  • 1st param U = int <--> enable<X>::type => Cannot deduce X
  • 2nd param V = bool <--> Y

Compiler is not designed to deduce X from equation int = enable<X>::type.
Therefore, compiler needs some help from developer.
Another parameter is required: Enable.

The below fixed snippet add the Enable class template parameter.
The compiler performs the following matching:

  • 1st param U =int <--> X
  • 2nd param V =bool<--> Y
  • 3rd param Enable=int <--> enable<X>::type (deduced X from 1st param)
    (3rd param is int because declaration class Enable=U means by default 3rd param same as 1st one)

Fixed snippet:

template <class T>
struct enable
{ typedef T type; };       // Enable always

template <class U, class V, class Enable = U>
struct Foo
{
    static int bar() { return 0; }
};

template <class X, class Y> // Compiler can deduce 'X'
struct Foo< X, Y, typename enable<X>::type >
{
    static int bar() { return 1; }
};

int main()
{
    return Foo<int, bool>::bar();
}