Clang-3.2 can compile and code behave as expected:
struct have_f { int f(int i) {return 10;} };
struct empty {};
template <class T>
struct outer {
T t;
// if T have f(), define outer_f()
template<class U=decltype(t.f(1))>
int outer_f(int i) { return t.f(i); }
};
int main() {
outer<have_f> o1;
outer<empty> o2;
// to silence unused var warning
return o1.outer_f(10) + sizeof(o2);
}
GCC of any version rejects with:
t.cc:13:6: error: ‘struct empty’ has no member named ‘f’
int outer_f(int i) { return t.f(i); }
^
Who is correct? Gcc or Clang?
Note, that there was similar question, without real answer.
I believe the issue is 14.6.3 [temp.nondep]:
The example given describes that an ill-formed expression within the template definition "could be diagnosed either [in the template definition] or at the point of instantiation".
The default template-argument (14.1p9)
U=decltype(t.f(1))
is a non-dependent name within the context of the instantiation ofstruct outer
(that is, it does not depend on a template argument to its own template) so it is ill-formed for the instantiation ofstruct outer
withT = struct empty
. The standard doesn't explicitly describe where default template-arguments are evaluated, but the only sensible conclusion is that they are treated as any other construct and evaluated at the point they occur (or, in this example, at the point of instantiation of thestruct outer
template). I don't see any latitude for the compiler to delay evaluation of non-dependent default template-arguments to contexts where SFINAE applies.Fortunately the solution is easy: just make the default template-argument
U
a dependent name: