2016-03-25 13 views
6

Supponiamo di avere la seguente classe:Perché non è possibile istanziare una coppia con un costruttore di copie "non const" mentre è possibile creare un'istanza senza?

struct A { 
    A() {} 
    A (A &) = delete; 
}; 

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

Il seguente codice non riuscirà a compilare (usando -std=c++11 con g++) con il seguente errore:

/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘struct std::pair’:

test.cpp:13:23: required from here

/usr/include/c++/5/bits/stl_pair.h:127:17: error: ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = A; _T2 = int]’ declared to take const reference, but implicit declaration would take non-const

constexpr pair(const pair&) = default; 

Secondo il messaggio di errore, vorrei assumere questo perché non è possibile instanciare il costruttore di copie predefinito a causa del qualificatore const sull'argomento std::pair.

Potrei capire perché questo non si compilerebbe senza lo = delete, perché non è possibile installare il costruttore di copie che prende un parametro std::pair const&.

Ma con il = delete, mi aspetto che il compilatore non istanzia un tale costruttore perché non può (per quanto ho capito). In realtà, questo costruttore di copia viene eliminato come dimostrato da questo pezzo di codice:

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

che non riesce:

test.cpp:11:23: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = A; _T2 = int]’

decltype(p1) p2(p1); 

In sostanza, la mia domanda è: Perché il compilatore non riesce a un'istanza di un costruttore di copia eliminata di std::pair?

+0

Vedere http://cplusplus.github.io/LWG/lwg-closed.html#2068 –

risposta

5

[class.copy]/8:

The implicitly-declared copy constructor for a class X will have the form

X::X(const X&) 

if each potentially constructed subobject of a class type M (or array thereof) 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&) 

Pertanto, se il costruttore di copia di std::pair<A, int> dovesse essere dichiarata implicitamente, sarebbe la forma pair::pair(pair &).

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

A function that is explicitly defaulted shall

  • be a special member function,

  • 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, and

  • not have default arguments.

Dal momento che la dichiarazione di pair(const pair&) = default; non ha lo stesso tipo di funzione dichiarata come il costruttore di copia che sarebbe stato implicitamente dichiarata, e si applica né eccezioni, il programma è mal-formata.

6

Se si desidera il costruttore di copia = delete, la forma corretta è: A(const A&) = delete;. Guarda come hai dimenticato che const? pair può essere utilizzato con un tipo non copiabile, anche di tipo non mobile.

Il tuo problema di istanza può anche essere dimostrato con:

struct A { 
    A(A&) = delete; 
}; 

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

o ...

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

In sostanza, pair= default sua copia ctor, e lo definisce come prendere un const pair&, ma uno uno dei tuoi tipi lo definisce per prendere un non-const &, quindi la generazione predefinita fallisce poiché non può passare è const & al tuo non-const &. Anche se il tuo è = delete, non importa, non arriva così lontano.

Un certificato di copia predefinito viene effettivamente eliminato se un membro o una classe base non è copiabile. Ma per capirlo, deve avere una funzione che è in grado di chiamare (anche se quella funzione viene cancellata). In questi casi, non può passare un const & a un non-const & in modo che non possa nemmeno capire di avere un ctor di copia cancellato. È plausibile che qualcosa nello standard possa essere scritto per accogliere questo caso limite.

Problemi correlati