When do special member functions of a template class come about?

When are special member functions (in particular, copy / move constructors and copy / move assignment operators) of an instance of a template class used? As soon as an instance of the class is created, or only when they are needed?

This happens 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; ^ 

assuming he is trying to instantiate the copy constructor immediately after creating the class instance.

GCC, however, compiles the code just fine, assuming that it will try to instantiate the copy constructor if it is really needed.

Which compiler behavior is correct?

(A similar mismatch is displayed for assignment operators.)

UPDATE This is because the copy constructor pair in this example is default ed, because if I changed its definition to

 pair(const pair& p) : first(p.first), second(p.second) {} 

then the code also goes into clang.

+8
c ++ copy-constructor c ++ 11 templates clang
source share
2 answers

The corresponding pass of the standard is [dcl.fct.def.default] / 1:

A function that is explicitly defaulted must [...] have the same declared function type (with the possible exception of different ref qualifiers, and except that in the case of a copy constructor or copy assignment operator, the parameter type can be a "reference on non-const T ", where T the class name of the member function), as if it were declared implicitly

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

The implicitly declared copy constructor will look like

X::X(const X&)

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

Otherwise, the constructor with the implicit declaration will look like

X::X(X&)

Therefore, this example is poorly formed (and should produce the diagnostics that you see):

 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 does not apply. Due to the clang error (which has already been fixed), remote copy constructors were incorrectly considered as having non-constant parameter types, which led to this error.

+2
source share

Take a look at section 14.7.1 of the current C ++ 11 standard. To quote from the project version n3242:

Implicit creation of a template specialization class causes implicit creation of declarations, but not default definitions or arguments, class member functions, member classes, static data elements and member templates; and this causes an implicit representation of member definitions by anonymous unions. If a class template member or template member has been explicitly created or explicitly specialized, a member specialization is implicitly created when a specialization is referenced in a context that requires a member definition exists; in particular, the initialization (and any associated side effects) of a static data member does not occur if the static data element itself is used in a way that requires the definition of a static data member.

So this means that when you use a class as a type, as described above, only declarations are created with it. Thus, the actual (default) implementation of the copy constructor should not be created, since this code is not required. Thus, GCC does this correctly, while Clang does not.

Also, your board suggests that Clang generate the default implementation for the copy constructor too soon, since your directly implemented copy constructor is also wrong (you cannot call the copy constructor for S , as you do in your own implementation). Since the default executable and your implementation should be the same in all respects (including instance creation time), I consider this a clang error.

+5
source share

All Articles