After seeing this question When is a C++ template instantiation type checked? , and wondering myself for quite some time the same thing I started to play with code to assimilate the knowledge. The answer gives clear and correct explanation. It mentions two-phase name lookup and the fact that the end of translation unit is also considered a point of instantiation for function templates. However I observed different behavior when using automatic return type deduction:
This is like the original code. It is correct and works as explained in the linked post:
class A;
class B;
template <class T> auto foo() -> T * {
A *pa = nullptr; // ignore pa being `nullptr`.
return static_cast<T *>(pa);
}
auto test() { return foo<B>(); }
class A {};
class B : public A {};
When using automatic return type deduction for the template foo
, the definitions of A
and B
must appear before the instantiation point of foo
:
Not working:
class A;
class B;
template <class T> auto foo() { // automatic return type deduction
A *pa = nullptr;
return static_cast<T *>(pa);
}
auto test() { return foo<B>(); }
class A {};
class B : public A {};
The error by gcc (4.9 and 5.2.1):
error: invalid static_cast from type ‘A*’ to type ‘B*’
Clang gives a similar error
Working:
class A;
class B;
template <class T> auto foo() { // automatic return type deduction
A *pa = nullptr;
return static_cast<T *>(pa);
}
class A {};
class B : public A {};
auto test() { return foo<B>(); }
Why it is happening? Why is that the rule about the end of compilation unit beeing considered a point of instantiation doesn't make the template instantiation legitimate anymore?
B
a member of typedecltype(test());
? – Eyelidfoo<B>()
)B
andA
are incomplete types. Thus, the compiler complains. – Bionomicsfoo
has an explicit return type, even ifA
andB
are incomplete types at the point if instantiation. See first example and the linked post. – Ethelfoo<B>
, one immediately aftertest
, one at the end of the TU. The cast is invalid at the first point but not the second, so this looks like it's ill-formed NDR. The reason for the error showing up in only the deduced return type case is likely that the compiler needed to determine the return type oftest
(which isn't a template) and so it instantiated the body offoo
at the first point rather than the second point. – Cadge