问题
Consider the following example:
template<typename T>
class Base
{
public:
inline void fooBase ()
{
T t; // The following error only occurs when class ABC is not defined at the end of the file: "error: t uses undefined class ABC"
}
protected:
};
class ABC;
class DEF;
class Derived : public Base<ABC>
{
public:
void fooDerived ()
{
DEF def; // error: def uses undefined class DEF
}
};
Derived derived;
void foo ()
{
derived.fooBase ();
}
class ABC {};
class DEF {};
Question(s)
- Why is the compiler happy with class
ABC
only defined at the end of the file? - Why is the definition not needed when declaring
Derived
, nor when declaring the globalfoo
function? - When are member functions of a templated class instantiated? Even when the function is made explicit inline, the function seems to be instantiated (at the end of the file) after the function is called in
foo ()
. - Is this behaviour standard C++? If so, does it depends on the C++ version used?
Note that fooDerived
generates an error as expected: the class should be (fully) defined before it is used.
Note that it is not necessary to answer all the questions separately, as they are rather different formulations of the same question.
Tested environment:
- MSVC (but I'm interested in cross platform compliance.)
- It seems to work (except for
DEF def;
as expected) on the three main compilers (GCC, CLang AND MSVC): https://godbolt.org/z/z_c7mc
回答1:
When are member functions of a templated class instantiated?
The declaration of a class template specialization's member function is instantiated along with the class specialization, but the definition is only instantiated when needed. Usually when the member function is called. So long as nothing uses the member function, the definition may go un-instantiated.
Your example calls the member function, so the definition must be instantiated.
There may however be multiple points of instantiation for a member function of a specialization. One is immediately before being used, but an additional one (that is always added) is at the end of the translation unit
[temp.point] (emphasis mine)
8 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.
Which brings me to the next point,fooBase
has two points of instantiations in the translation unit you show. In one ABC
is incomplete, while in the other it has been completed. Under the paragraph above, your program is ill-formed, no diagnostic required. A compiler can be silent about the violation, all the while emitting some code the seems to work. But that does not make the program valid. If the standard is updated in the future to require a diagnostic in this case, the illegal code will fail to build. It may even fail now if compilers wish to diagnose it.
来源:https://stackoverflow.com/questions/59435038/when-are-member-functions-of-a-templated-class-instantiated