When are the special member functions (specifically, copy/move constructors and copy/move assignment operators) of a template class instantiated? As soon as the class itself is instantiated, or only when they are needed?
This comes up in the following situation:
template <class T, class U>
struct pair
{
T first;
U second;
pair() : first(), second() {}
pair(const pair&) = default;
};
struct S
{
S() {}
S(const S&) = delete;
S(S&&) = default;
};
int main()
{
pair<int, S> p;
}
Clang refuses to compile this code, with the following errors:
test.cpp:9:5: error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be
non-const
pair(const pair&) = default;
^
test.cpp:21:18: note: in instantiation of template class 'pair<int, S>' requested here
pair<int, S> p;
^
suggesting that it tries to instantiate the copy constructor as soon as the class is instantiated.
GCC, however, compiles the code just fine, suggesting that it would only try to instantiate the copy constructor if it was actually needed.
Which compiler's behaviour is correct?
(A similar discrepancy is exhibited for assignment operators.)
UPDATE: This has something to do with the fact that the copy constructor of pair
in this example is default
ed, because if I change its definition to
pair(const pair& p) : first(p.first), second(p.second) {}
then the code passes clang as well.
The bodies of template classes and inline (or static) template functions are always instantiated implicitly when their definitions are needed. Member functions of template classes are not instantiated until they are used. Other template items can be instantiated by using explicit instantiation.
Template instantiation involves generating a concrete class or function (instance) for a particular combination of template arguments. For example, the compiler generates a class for Array<int> and a different class for Array<double>.
To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation.
Have a look at section 14.7.1 of the current C++11 standard. To quote from the n3242 version of the draft:
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions. Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
So, this means, when you use a class as a type as above only the declarations are instantiated with it. So the actual (defaulted) implementation of the copy constructor should not be instantiated, as it is not needed in the above code. So GCC is handling this correctly, whereas Clang does not.
Also your edit suggests, that Clang is generating the implementation for the default copy constructor too early, since your directly implemented copy constructor is faulty as well (you cannot call the copy constructor for S
as you are doing in your own implementation). Since the defaulted implementation and your implementation should be the same in all respects (including the time of instantiation), I would consider this a clang bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With