Why is it impossible to pair with the constructor of the copy of "non const", while without the possibility of creating it?

Suppose you have the following class:

struct A { A () {} A (A &) = delete; }; int main() { std::pair<A, int> p1; return 0; } 

The following code will not be able to compile (using -std=c++11 with g++ ) with the following error:

/usr/include/++/5/bits/stl_pair.h: When creating 'struct std :: pair:

test.cpp: 13: 23: required from here

/usr/include/++/5/bits/stl_pair.h: 127: 17: error: 'constexpr std :: pair <_T1, _T2> :: pair (const std :: pair <_T1, _T2> &; ) [with _T1 = A; _T2 = int] is declared to accept a const reference, but an implicit declaration will accept a non-constant

 constexpr pair(const pair&) = default; 

According to the error message, I would suggest that this is because it is not possible to create a default copy constructor due to the const qualifier in the std::pair argument.

I could understand why this would not compile without = delete , because it is impossible to create a copy constructor that takes the std::pair const& parameter.

But with = delete I would expect the compiler to not create such a constructor, because it cannot (as far as I understand). In fact, this copy constructor is deleted, as shown in this code snippet:

 std::pair<A, int> p1; decltype(p1) p2(p1); 

What fails:

test.cpp: 11: 23: error: using the remote function 'constexpr std :: pair <_T1, _T2> :: pair (const std :: pair <_T1, _T2> &) [with _T1 = A; _T2 = int]

 decltype(p1) p2(p1); 

Basically, my question is: why can't the compiler create an instance of the instantiated remote copy of std::pair ?

+6
source share
2 answers

[class.copy] / 8 :

The implicitly declared copy constructor for class X will take the form

 X::X(const X&) 

if each potentially constructed subobject of type of class M (or array) has a copy constructor, the first parameter of which is of type const M& or const volatile M& . Otherwise, the implicitly declared copy constructor will take the form

 X::X(X&) 

Therefore, if the copy constructor std::pair<A, int> must be declared implicitly, it will take the form pair::pair(pair &) .

[dcl.fct.def.default] / 1 :

The function explicitly set by default should

  • - special member function,

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

  • have no default arguments.

Since declaration pair(const pair&) = default; does not have the same declared function type as the copy constructor, which would be implicitly declared, and no exceptions are applied, the program is poorly formed.

+5
source

If you want = delete copy constructor, the correct form is: A(const A&) = delete; . See how you forgot that const ? pair can be used with a non-copyable type, even with a non-movable type.

Your instance creation problem can also be demonstrated with:

 struct A { A(A&) = delete; }; struct B : A { B(const B&) = default; }; 

or...

 struct B { B(const B&) = default; A a; }; 

Basically, pair = default its copy of ctor and defines it as accepting const pair& , but one of your types defines it to accept non-const &, therefore, the default generation fails because it can Skip its const & to your non-const & . Even if your = delete ed, it doesn't matter, it's not that far.

By default, a ctor copy will be effectively deleted if the member or base class is not copied. But in order to understand this, he must have a function that he can call (even if this function is deleted). In these cases, it cannot pass const & to non-constant & therefore it cannot even understand that you have a remote copy of ctor. Of course, something in the standard could be written to accommodate this edge case.

+6
source

All Articles