template <class T>
void Yeap(T);
int main() {
Yeap(0);
return 0;
}
template <class T>
void YeapImpl();
struct X;
template <class T>
void Yeap(T) {
YeapImpl<X>(); // pass X to another template
}
template <class T>
void YeapImpl() {
T().foo();
}
struct X {
void foo() {}
};
Note that struct X
is not defined until the very end. I used to believe that all odr-used names must be complete at the point of the instantiation. But here, how can the compiler treat it as a complete type prior to its definition?
I have checked the binding rules and lookup rules of dependent name and function template instantiation in cppreference, but none of them can explain what is happening here.
I believe this program is ill-formed, no diagnostic required.
[temp.point]/8 reads, editing out the irrelevant parts:
YeapImpl<X>
has two points of instantiation: where it is called on the commented line in the question and at the end of the translation unit. In the first point of instantiation,X
is incomplete which would make the body of the function ill-formed. In the second point of instantiation,X
is complete which makes the body well-formed.Those two specializations have [very] different meanings.