2015-04-23 18 views
17

GCC (testato con 4.9) accetta la seguente TestCase:sovraccarico differenza di risoluzione tra gcc e clang che coinvolge mossa costruttore e 'Derivato (Base &&)' costruttore

struct Base {}; 

struct Derived : Base { 
    Derived(); 
    explicit Derived(const Derived&); 
    explicit Derived(Derived&&); 
    explicit Derived(const Base&); 
    Derived(Base&&); 
}; 

Derived foo() { 
    Derived result; 
    return result; 
} 

int main() { 
    Derived result = foo(); 
} 

Clang (testato con 3.5) rifiuta con il seguente messaggio di errore:

test.cpp:13:10: error: no matching constructor for initialization of 'Derived' 
    return result; 
     ^~~~~~ 
test.cpp:8:5: note: candidate constructor not viable: no known conversion from 'Derived' to 'Base &&' for 1st argument 
    Derived(Base&&); 
    ^
test.cpp:4:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 
    Derived(); 
    ^

Chi ha ragione?

risposta

14

Credo che Clang sia corretto qui. GCC non dovrebbe accettare il codice.

Il motivo è la risoluzione modo di sovraccarico per i costruttori per la copia oggetto che si verificano in un comunicato return è specificato in [class.copy] p32 (sottolineatura mia):

Quando i criteri per l'elisione di un costruttore di copia/spostamento sono soddisfatte , [...] e l'oggetto da copiare è designato da un valore di lvalue, [...], la risoluzione di sovraccarico per selezionare il costruttore per la copia è il primo eseguito come se l'oggetto fosse designato da un valore di rvalue. Se la prima risoluzione sovraccarico fallisce o non è stata eseguita, o se il tipo di primo parametro del costruttore selezionato non è un rvalue riferimento al tipo di oggetto (possibilmente cv-qualificato), sovraccaricare risoluzione viene eseguita nuovamente considerando l'oggetto come un lvalue.

In questo esempio, i criteri di elisione sono soddisfatte (dal primo punto in [class.copy] p31) e l'oggetto da copiare è indicata con un lvalue, quindi questo punto si applica.

La risoluzione del sovraccarico viene prima tentata come se l'oggetto fosse designato da un valore di rvalue. I costruttori explicit non sono candidati (vedere sotto per una spiegazione del perché), quindi è selezionato il costruttore Derived(Base&&). Tuttavia, questo rientra in "il tipo del primo parametro del costruttore selezionato non è un riferimento di rvalue al tipo dell'oggetto" (invece, è un riferimento di rvalue al tipo della classe base dell'oggetto), quindi la risoluzione di sovraccarico dovrebbe essere eseguita di nuovo considerando l'oggetto come un lvalue.

Questa seconda risoluzione di sovraccarico non riesce, poiché l'unico costruttore valido (ancora, i costruttori non sono candidati) ha un parametro di riferimento rvalue, che non può essere associato al lvalue. Clang mostra l'errore di errore della risoluzione di sovraccarico risultante.


Per completare la spiegazione, ecco perché explicit costruttori non sono candidati sia per la risoluzione di sovraccarico (tutti corsivo è mio).

Innanzitutto, [dcl.init] p15 dice che:

L'inizializzazione che si verifica nella = forma di tutore o uguale-inizializzatore o condizione (6,4), così come in argomento passing, restituisce la funzione, generando un'eccezione (15.1), gestendo un'eccezione (15,3) e l'inizializzazione del membro aggregato (8.5.. 1), è chiamato copia-inizializzazione"

Avanti, guardiamo [over.match.ctor] p1:

per copia-inizializzazione, le funzioni candidati sono tutta la conversione costruttori (12.3.1) di quella classe

Infine, vediamo che explicit costruttori non stanno convertendo costruttori in [class.conv.ctor] p1:

Un costruttore ha dichiarato senza la funzione-specifier explicit specifica una conversione dai tipi dei suoi parametri al tipo della sua classe. Tale costruttore è chiamato conversione costruttore.

+0

Ma dice "se il tipo se il primo parametro non è un riferimento di rvalore, viene eseguito di nuovo". Quindi, dato che lo è, la risoluzione del sovraccarico non viene eseguita di nuovo. – Columbo

+0

@Columbo: Dice "se il tipo del primo parametro non è un riferimento di rvalore ** al tipo di oggetto **", la risoluzione di sovraccarico viene eseguita nuovamente. Qui, è un riferimento di rvalue, ma non al tipo dell'oggetto. (Si noti che "l'oggetto" qui si riferisce a "l'oggetto da copiare" dall'inizio del paragrafo, che è un oggetto di tipo "Derivato".) – HighCommander4

+0

Ah, giusto, corretto. – Columbo

Problemi correlati