Leggendo ancora e ancora lo standard, penso che questo sia un bug.
Cosa dice lo standard?
8.5.1/2: Quando un aggregato viene inizializzato da una lista di inizializzazione, come specificato in 8.5.4, gli elementi della lista di inizializzazione sono presi come inizializzatori per i membri dell'aggregato, in aumento di pedice o ordine di membro. Ogni membro è inizializzato dalla copia dalla clausola initializer corrispondente .
Si spiega che:
8,5/14: (...) si chiama copia-inizializzazione. [Nota: l'inizializzazione della copia può richiedere uno spostamento (12.8). -end note]
Ma non ho trovato prove in 12.8 che nel tuo caso specifico sarebbe necessaria una mossa.
8.5.4/3 In caso contrario, se T è un tipo di classe, i costruttori sono considerati. Se T ha un costruttore inizializzatore-lista, l'argomento lista consiste dell'elenco inizializzatore come un singolo argomento; altrimenti, l'elenco degli argomenti è costituito dagli elementi dell'elenco di inizializzazione. I costruttori applicabili vengono enumerati e viene selezionato il migliore tramite la risoluzione di sovraccarico (13.3).
Quindi in linea di principio il codice dovrebbe funzionare!
È un errore? Provare il modo sperimentale
Ho commentato l'eliminazione del costruttore di spostamenti, per beneficiare del costruttore di spostamenti impliciti.Stranamente, ho quindi ricevuto il seguente messaggio di errore:
Compilation error time: 0 memory: 3232 signal:0
prog.cpp: In constructor 'Aggr::Aggr()':
prog.cpp:19:28: error: use of deleted function 'A::A(const A&)'
Aggr() : arr{{"a"}, {"b"}} {}
^
prog.cpp:10:3: note: declared here
A(const A&) = delete
Così ora si lamenta di un costruttore di copie mancante!
Ancora più strano, ho quindi fornito il mio costruttore di mosse invece dell'implicito: qui ha compilato il codice con successo !!
Finalmente disponibile sia una copia e una mossa e aggiunti alcuni tracciamento:
class A {
private:
std::string s;
public:
A() = delete;
A(const A&) { std::cout<<"copy\n";} //= delete;
A(A&&) { std::cout<<"move\n";} //= delete;
A(const std::string &a) : s(a) { std::cout<<"string ctor\n";}
};
E quando si crea un oggetto Aggr
, visualizza solo:
string ctor
string ctor
dimostrando che l'elemento di matrice è inizializzato forma il costruttore di stringhe usando la copia elision come ci saremmo aspettati.
Tutti questi test sono stati eseguiti con gcc-9.4.2 su ideone con opzione C++ 14.
Conclusione
Il fatto che lo stesso codice non riesce a compilare con implicita mossa ctor e riesce con una mossa ctor definito dall'utente appare molto sul serio come un insetto.
Il fatto che il costruttore di movimento non venga utilizzato quando è disponibile rafforza questa impressione.
Di conseguenza, ho segnalato this bug.
Perché è "A &&'? – ZivS
@ZivS un riferimento di valore – bolov
probabilmente rilevante per il problema: http://stackoverflow.com/questions/26685551/how-to-initialize-array-of-classes-with-deleted-copy-constructor-c11 – marcinj