According to Template parameters and template arguments on cppreference.com:
A template argument for a type template parameter must be a type-id, which may name an incomplete type
That means that this example (copied from that page) is legal:
// Example 0
template <typename T>
struct X {};
struct A;
int main() {
X<A> x1;
}
and, I suppose, also this is legal:
// Example 1
template <typename T>
struct X {};
struct A {
X<A> x1;
};
int main() {
A a1;
}
Now, let's complicate a bit the code:
// Example 2
template <typename T>
struct X {
using type = typename T::type;
};
struct A {
using type = int;
X<A>::type x1;
};
int main() {
A a1;
}
In this case, A
is still an incomplete type when used as template argument, and the code compiles. Now, if I change the order of the lines in A
:
// Example 3
template <typename T>
struct X {
using type = typename T::type;
};
struct A {
X<A>::type x1; // ERROR HERE
using type = int;
};
int main() {
A a1;
}
the code does not compile anymore. Clang error message is something like no type named 'type' in 'A'
, but also GCC, ICC and MSVC return similar errors (see this demo on godbolt.com), and this seems almost identical to that of typedefs on CRTP, discussed here.
Anyway, the behavior seems reasonable: compilers use all the properties of A
defined at the point X<A>
is used.
But what does the C 14 (or later) standard say about it? Is it legal to rely on the behavior of the working Example 2?
CodePudding user response:
This is CWG issue 287.
You can look at the reasoning there, but my understanding from it is that the consensus is that the standard technically currently doesn't allow either your last or second-to-last example, since the point of instantiation of X<A>
will be before the definition of A
, where typename T::type
cannot be formed.
However, as indicated in the proposed resolution, it is intended that even though the point of instantiation would be before the definition of A
, names declared in A
before the point requiring instantiation of X<A>
shall still be visible to the instantiation.
That is what the compilers implement and you observe.