Prima di continuare a leggere questo, leggere prima Is there a difference in C++ between copy initialization and direct initialization?, assicurarsi di aver capito di cosa sta parlando.Inizializzazione della copia C++ e inizializzazione diretta, caso strano
cercherò di riassumere la regola qui prima (lettura standard n3225 8,5/16, 13.3.1.3, 13.3.1.4, 13.3.1.5 e),
1) Per l'inizializzazione diretta, tutti i costruttori saranno considerati come il set di sovraccarico, la risoluzione di sovraccarico selezionerà il migliore in base alle regole di risoluzione di sovraccarico.
2) Per l'inizializzazione della copia e il tipo di origine è uguale al tipo di destinazione o derivato dal tipo di destinazione, la regola è uguale a precedente salvo che solo i costruttori di conversione (costruttori senza esplicito) verranno considerati come set di overload. Questo in realtà significa che i costruttori di copia/spostamento espliciti non saranno considerati nel set di overload.
3) Per i casi di inizializzazione della copia non inclusi in (2) sopra (il tipo di origine è diverso dal tipo di destinazione e non derivato dal tipo di destinazione), consideriamo prima le sequenze di conversione definite dall'utente che possono convertire dal tipo di origine al tipo di destinazione o (quando viene utilizzata una funzione di conversione) a una classe derivata. Se la conversione ha esito positivo, il risultato viene utilizzato per inizializzazione diretta l'oggetto di destinazione.
3.1) Durante questa sequenza di conversione definita dall'utente, verranno considerati sia i cori di conversione (non espliciti) che le funzioni di conversione non esplicite, in base alle regole in 8.5/16 e 13.3.1.4.
3.2) Il valore del risultato sarà inizializzazione diretta l'oggetto di destinazione, come regole elencate in (1), vedere 8.5/16.
Ok, abbastanza per le regole, diamo un'occhiata ad un codice strano, che non ho davvero idea di dove il mio ragionamento sia sbagliato, o che tutti i compilatori abbiano torto. Per favore aiutami, grazie.
struct A
{
A (int) { }
A() { }
explicit A(const A&) { }
};
struct B
{
operator A() { return 2; }
//1) visual c++ and clang passes this
//gcc 4.4.3 denies this, says no viable constructor available
};
int main()
{
B b;
A a = b;
//2) oops, all compilers deny this
}
Nella mia comprensione, per (1),
operator A() { return 2; }
Poiché C++ ha una regola che funziona ritorno è preso come copia-inizializzazione, secondo la regola precedente, 2 saranno dapprima implicitamente convertito ad A, che dovrebbe essere OK perché A ha un costruttore A (int). Quindi il valore provvisorio convertito verrà utilizzato per inizializzare direttamente l'oggetto restituito, il che dovrebbe essere corretto anche perché l'inizializzazione diretta può fare uso del costruttore di copie esplicito. Quindi GCC ha torto.
Per (2),
A a = b;
Nella mia comprensione, innanzitutto b viene convertito implicitamente A, dall'operatore A(), e quindi il valore convertito è utilizzato per direct-inizializzare una, che può Chiama ovviamente il costruttore di copie esplicite? Quindi questo dovrebbe passare la compilazione e tutti i compilatori sono sbagliati?
Nota che per (2), sia visual C++ che clang ha un errore simile a, "Errore, impossibile convertire da B a A", ma se rimuovo la parola chiave esplicita nel costruttore di copie di A, l'errore è andato ..
Grazie per la lettura.
modificare 1
perché qualcuno ancora non ha ottenuto quello che volevo dire, cito il seguente norma da 8,5/16,
In caso contrario (cioè, per i restanti della copia casi di inizializzazione), sequenze di conversione definite dall'utente che possono convertire dal tipo di origine a il tipo di destinazione o (quando viene utilizzata una funzione di conversione ) aLa classe derivataè elencata come descritto in 13.3.1.4, e la migliore viene scelta tramite la risoluzione di sovraccarico (13.3). Se la conversione non può essere eseguita o è ambigua, l'inizializzazione non è corretta. La funzione selezionata viene chiamata con l'espressione di inizializzazione come argomento ; se la funzione è un costruttore , la chiamata inizializza un temporaneo della versione cv-non qualificata del tipo di destinazione. Il temporaneo è un valore di prvalore. Il risultato della chiamata (che è il temporaneo per caso costruttore) viene poi utilizzato per diretta inizializzazione, secondo le regole di cui sopra , l'oggetto che è la destinazione del copia-inizializzazione. In alcuni casi, a è consentita l'implementazione di eliminare la copia inerente a questa inizializzazione diretta creando il risultato intermedio direttamente in l'oggetto da inizializzare; vedi 12.2, 12.8.
Si noti che ha menzionato l'inizializzazione diretta dopo la conversione definita dall'utente. Il che significa, a mio modo di vedere, che il codice seguente obbedirà alle regole come quello che ho commentato, il che è confermato da clang, coomeau online, visual C++, ma GCC 4.4.3 fallisce sia (1) che (2). Anche se questa è una regola strana, ma segue il ragionamento dallo standard.
struct A
{
A (int) { }
A() { }
explicit A(const A&) { }
};
int main()
{
A a = 2; //1)OK, first convert, then direct-initialize
A a = (A)2; //2)oops, constructor explicit, not viable here!
}
Comeau Online accetta l'intero snippet di codice come scritto. –
ok, grazie. Questo mi dà una certa sicurezza che il mio ragionamento non stia andando nella direzione sbagliata.^_^ – user534498
@James McNellis: Tuttavia, Comeau Online rifiuta il codice nella mia risposta, anche se secondo il ragionamento di OP dovrebbe essere accettato. – AnT