问题
The question in the title is clear enough. To be more specific, consider the following example:
#include <type_traits>
template <typename T>
struct is_complete_helper {
template <typename U>
static auto test(U*) -> std::integral_constant<bool, sizeof(U) == sizeof(U)>;
static auto test(...) -> std::false_type;
using type = decltype(test((T*)0));
};
template <typename T>
struct is_complete : is_complete_helper<T>::type {};
// The above is an implementation of is_complete from https://stackoverflow.com/a/21121104/5376789
template<class T> class X;
static_assert(!is_complete<X<char>>::type{});
// X<char> should be implicitly instantiated here, an incomplete type
template<class T> class X {};
static_assert(!is_complete<X<char>>::type{}); // #1
X<char> ch; // #2
This code compiles with GCC and Clang.
According to [temp.inst]/1:
Unless a class template specialization has been explicitly instantiated or explicitly specialized, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.
X<char>
is implicitly instantiated due to static_assert(!is_complete<X<char>>::type{})
, which generates an incomplete type.
Then, after the definition of X
, #1
suggests that X<char>
is not instantiated again (still incomplete) while #2
suggests that X<char>
is indeed instantiated again (becomes a complete type).
Is a specialization implicitly instantiated if it has already been implicitly instantiated? Why is there a difference between #1
and #2
?
An interpretation from the standard is welcome.
回答1:
Is a specialization implicitly instantiated if it has already been implicitly instantiated?
No. According to [temp.point]/8:
A specialization for a class template has at most one point of instantiation within a translation unit.
x<char>
need only be instantiated once, and it's not when it's named in the first static assertion, only before ch
. But, [temp.point]/8 also says
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. [...] 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.
And is_complete_helper::test
is a member function template whose declaration is instantiated before the static assertion. So it must also have an instantiation at the end of the TU. Where it will likely give a different result. So this trait is depending on an ill-formed NDR construct.
来源:https://stackoverflow.com/questions/52201121/is-a-specialization-implicitly-instantiated-if-it-has-already-been-implicitly-in