This code is surely ill-formed, because Foo
is specialized after an instantiation point:
template <typename T>
struct Foo {
int a;
};
Foo<int> x = { 42 };
template <>
struct Foo<int> {
const char *a;
};
Foo<int> x = { "bar" };
It is ill formed because of the part of the standard I've put emphasis:
A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
Now, is this code ill-formed?
struct A;
template <typename> class Foo { };
Foo<A> foo; // note A is incomplete here
struct A {};
Does the ill-formedness change, if Foo
declared like this?
struct A;
template <typename T>
struct Foo {
Foo() {
new T;
}
};
Foo<A> foo; // note A is incomplete here
struct A {};
I asked this question, because of the discussion under this question.
Note, this is not a duplicate. That question is about why the code compiles, this question is about whether it is ill-formed. They differ, because an ill-formed program isn't necessarily a non-compiling program.
Note, with clang and gcc, my example with new T
compiles, while this example (T
as a member) doesn't:
struct A;
template <typename T>
struct Foo {
T t;
};
Foo<A> foo; // note A is incomplete here
struct A {};
Maybe both are ill-formed, and diagnostic is given only for this last case?
vector<Incomplete>
would also be for the same reason. But we can havevector
s of incomplete types just fine. – BarryFoo<int> x = { "bar" };
as POI.Foo<int>
's meaning is different there than atFoo<int> x = { 42 };
. Isn't this correct thinking? – geza