Using `extern template` to prevent implicit instantiation of a template class
Why does my code snippet link? What is actually happening here?
Well, there's nothing to link. For one has to consider the effects of the explicit instantiation. From n3337:
[temp.explicit] (emphasis mine)
10 Except for inline functions and class template specializations, explicit instantiation declarations have the effect of suppressing the implicit instantiation of the entity to which they refer. [ Note: The intent is that an inline function that is the subject of an explicit instantiation declaration will still be implicitly instantiated when odr-used ([basic.def.odr]) so that the body can be considered for inlining, but that no out-of-line copy of the inline function would be generated in the translation unit. — end note ]
So the implicit instantiation of the class template specialization X<int>
, is not suppressed. It's also an aggregate, so its initialization occurs inline, and we get nothing to link against. However, if it had any members, those would be suppressed under paragraph 8:
An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below.
So if you had instead of an aggregate something akin to this:
template <typename>
struct X {
X();
};
template <typename T>
X<T>::X() {}
extern template struct X<int>;
int main()
{
X<int>{};
}
That would fail as you expect, since it ODR uses a constructor whose definition is never instantiated. The declaration is instantiated, because the enclosing specialization is instantiated, as mentioned above. But we never get any definition, under the suppressing effect of the explicit instantiation declaration.
Does this mean that the code snippet I posted is ill-formed, NDR?
Yes, by the exact sentence from [temp.explicit]/13 that you quoted. "An entity" means just that. It does not matter if an explicit instantiation declaration otherwise have no normative effect.