NOTE: I opened a question here about whether OPs code is actually valid. My rewritten example below will work in any case.
but I would like to know if the code is legal C++11
It is, although the default template argument may be considered a bit unusual. I personally like the following style better, which is similar to how you (read: I) write a trait to check for a function's existence, just using a non-type template parameter and leaving out the decltype
:
#include <type_traits>
namespace detail{
template<int> struct sfinae_true : std::true_type{};
template<class T>
sfinae_true<(T::f(), 0)> check(int);
template<class>
std::false_type check(...);
} // detail::
template<class T>
struct has_constexpr_f : decltype(detail::check<T>(0)){};
Live example.
Explanation time~
Your original code works? because a default template argument's point of instantiation is the point of instantiation of its function template, meaning, in your case, in main
, so it can't be substituted earlier than that.
§14.6.4.1 [temp.point] p2
If a function template [...] is called in a way which uses the definition of a default argument of that function template [...], the point of instantiation of the default argument is the point of instantiation of the function template [...].
After that, it's just usual SFINAE rules.
? Atleast I think so, it's not entirely clear in the standard.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…