Why does SFINAE not work here - c++11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct I_Have_No_Value;
struct I_Have_Value { static const int value {};};
template<typename T> struct Error {static const int value {T::value};};

template<int I> struct void_t_indirection {using type = void;};
template<int I> using void_t = typename void_t_indirection<I>::type;

template<typename T, typename =  void>
struct A {
  A() {std::printf("Base-Case chosen\n");}
};

template<typename T>
struct A<T, void_t<Error<T>::value>> {
  A() {std::printf("Specialization chosen\n");}
};

int main() {
  A<I_Have_No_Value> a0{};
  A<I_Have_Value> a1{};
}

Produces an error, while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct I_Have_No_Value;
struct I_Have_Value { static const int value {};};
template<typename T> struct Error {static const int value {T::value};};

template<int I> struct void_t_indirection {using type = void;};
template<int I> using void_t = typename void_t_indirection<I>::type;

template<typename T, typename =  void>
struct A {
  A() {std::printf("Base-Case chosen\n");}
};

template<typename T>
struct A<T, void_t<T::value>> {
  A() {std::printf("Specialization chosen\n");}
};


int main() {
  A<I_Have_No_Value> a0{};
  A<I_Have_Value> a1{};
}

works.

Why?
{GCC 4.8.2 / Ubuntu 14.04}
Last edited on
With A<I_Have_No_Value> => struct A<I_Have_No_Value, void_t<Error<I_Have_No_Value>::value>>,
there is no substitution failure; however, there is an instantiation failure.

oh ok...I thought over what you wrote for like 2 min and now I think I get it. Thought those kind of failures (instantiation faliures) let SFINAE kick in too. But now I am comprehending it as follows:

<1> Check if the instantiation would be correct - as if for example you were defining a variable
of that type independently somewhere then that should be doable.

<2> If that is fine then go ahead and try to access the stuff of the instantiated type which you would substitute there. If that fails then it's SFINAE candidate. However if <1> fails then it's like a hard error.

Is that fine?

Just one more quick question on the same:

Going on those lines if you have

1
2
template<typename T>
struct A<T, typename One<Two<typename T::type>::value>::type> { };


<3> if typename T::type is valid, Two<typename T::type>::value is valid, One<.....> is valid but typename One<....>::type is invalid, then SFINAE would kick in and the specialization would be discarded. But would all the prior instantiations cause the compiler to actually generate code for types T , Two<...> and One<...>?

<4> if all of them are valid and specialization is chosen will the code for those be generated in the object code?

I mean is it required by the standard/logic (Not talking about optimizer involvement etc)?

note- Consider I'm using them only for SFINAE, not using them (struct A is empty above}.
> <1> Check if the instantiation would be correct

Check if argument substitution is possible.


> <2> If that is fine then go ahead and try to access the stuff of the instantiated type

Yes. If substitution is possible and the specialisation is selected, attempt to instantiate the specialisation by instantiating substituted types / evaluating substituted expressions.

Only the failures in the types and expressions in the immediate context of the function type or its template parameter types are SFINAE errors. If the evaluation of a substituted type/expression causes a side-effect such as instantiation of some template specialization, generation of an implicitly-defined member function, etc, errors in those side-effects are treated as hard errors. http://en.cppreference.com/w/cpp/language/sfinae



> <4> if all of them are valid and specialization is chosen will the code for those be generated in the object code?

Only the chosen specialisation and its dependencies would be instantiated.


Consider using the metafunction std::enable_if<>. It makes SFINAE constructs easier to write and understand.
http://en.cppreference.com/w/cpp/types/enable_if
Last edited on
thanks a ton ! Marking it solved.
Topic archived. No new replies allowed.