简体   繁体   中英

When are special member functions of a template class instantiated?

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.

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.

The relevant passage of the standard is [dcl.fct.def.default]/1:

A function that is explicitly defaulted shall [...] have the same declared function type (except for possibly differing ref-qualifiers and except that in the case of a copy constructor or copy assignment operator, the parameter type may be "reference to non-const T ", where T is the name of the member function's class) as if it had been implicitly declared

This rule applies even if the defaulted function is never used. Now, [class.copy]/9 says:

The implicitly-declared copy constructor will have the form

X::X(const X&)

if [...] for all the non-static data members of X that are of a class type M [...], each such class type has a copy constructor whose first parameter is of type const M& or const volatile M& .

Otherwise the implicitly-declared copy constructor will have the form

X::X(X&)

Therefore, an example like this is ill-formed (and should produce the diagnostics you are seeing):

struct A {
  A();
  A(A&); // Note, non-const type A in copy constructor
};
template<typename T>
struct B {
  T t;
  B();
  B(const B&) = default;
};
B<A> b; // error, B<A>::B(const B&) is defaulted but has the wrong type

However, in your example, this rule doesn't apply. Due to a clang bug (which is already fixed), deleted copy constructors were incorrectly considered to have non-const parameter types, leading to this error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM