This code fails to compile in most compilers but at first I intuitively expected SFINAE to protect me:
typedef void (*A)();
template < typename T >
st
SFINAE won't protect you there, the error happens after type deduction. However, this should work:
template < typename T, typename Type = typename T::type >
struct a_metafun { typedef Type type; };
By accesing T::type
in a default template parameter we cause this to happen at substitution time, and at that time SFINAE kicks in.
Edit: After thinking some more, I'm not exactly sure why your current implementation fails. I think is because a_metafun
has a member type type
, one that causes a compilation error; it would be different if a_metafun
didn't have a member type type
at all.
In C++03 specification, the rule of SFINAE is a little vague, allowing compiler authors to go to any length to find substitution failure to result in SFINAE. The relevant text §14.8.2/2 from C++03 says,
-
[...] If a substitution in a template parameter or in the function type of the function template results in an invalid type, type deduction fails [...]
It further explains few reasons for failure, but none of them actually says at what point the substitution failure should be considered as SFINAE. So I guess, your code may work fine in C++03 (or may not, depending on how the compiler authors interpret the text. It is confusing to me anyway).
But the wordings in C++11 has been improved removing the vagueness. It says in §14.8.2/8,
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as part of the substitution process. —end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
The term "immediate context" is interesting, and I think it applies to your situation. More specifically, the substitution failure in the meta-function a_metafun
is not considered "immediate context" of the function-type. It is ill-formed in C++11, not SFINAE.
But then, even though C++11 has introduced the phrase "immediate context" to make the text slightly better, still the definition of the phrase isn't clear enough. Here is one active issue: