2013-03-21 15 views
11

Il seguente esempio deve essere compilato?Assegnazione di questo puntatore al riferimento di rima a un puntatore

struct B; 
struct A 
{ 
    A(B*&&){} 
}; 

struct B : A 
{ 
    B() : A(this){} 
}; 

int main(){} 

Su LWS con clangore compila, ma con gcc ottengo:

conversione non noto per argomento 1 da 'B * const' a 'B * & &'

e se aggiungo uno const viene compilato.

Vorrei sottolineare, inoltre, MSVC ottiene troppo male:

non può convertire il parametro 2 da 'B * const' a 'B * & &'

così sembra abbiamo un bug in due compilatori.

di bug

MSVC bug link

GCC bug link

+1

Per informazioni - questo compila sul compilatore Intel C++ (13.1) – teppic

risposta

8

Sì, che dovrebbe compilare.

È corretto implementare this come cv T* const (dove CV è il CV-qualificazioni per la funzione, se presente, e T è il tipo di classe). this non è const, solo un'espressione di valore di un tipo predefinito (non modificabile).

Molte persone pensano che, poiché non è possibile modificare this deve essere const, ma come Johannes Schaub - litb ha commentato una volta molto tempo fa, una spiegazione molto migliore è qualcosa di simile:

// by the compiler 
#define this (__this + 0) 

// where __this is the "real" value of this 

Qui è chiaro che si può 't modificare this (ad esempio, this = nullptr), ma anche cancellare no const è necessario per tale spiegazione. (E il valore che hai nel tuo costruttore è solo il valore del temporaneo.)

+0

In realtà è specificato che non possiamo modificare 'questo'? Ovviamente non possiamo farlo quando è un prvalore, ma cosa succede se lo leghiamo a un riferimento di valore e lo modifichiamo attraverso quello? –

+0

Interessante, quindi significa [la risposta selezionata a questa domanda SO] (http://stackoverflow.com/questions/7341607/so-what-is-the-type-of-this-why-is-this-not- a-lvalue) è sbagliato? –

+0

@sftrabbit: è un effetto collaterale di esso è un prvalore e un tipo predefinito. Tali oggetti non possono essere trattati come lvalue (assegnati o modificati in generale). Questo non si applica ai tipi definiti dall'utente perché quindi abbiamo sovraccarico dell'operatore e cosa avete. È possibile richiamare una funzione membro su un valore rval, ad esempio. – GManNickG

6

dico clang è giusto - il codice dovrebbe compilare. Per qualche ragione, GCC considera il puntatore this sia const nonostante la seguente:

Il tipo di this in una funzione membro di una classe X è . Se la funzione membro è dichiarata const, il tipo di questo è const X*, se la funzione membro è dichiarata volatile, il tipo di questo è volatile X* e se la funzione membro è dichiarata const volatile, il tipo di questo è const volatile X*.

Quindi in questo caso, dovrebbe essere un this prvalue B* e perfettamente associabile a B*&&. Tuttavia, si noti che quando si associa this a un riferimento di rvalue, il valore di this verrà copiato in un oggetto temporaneo e il riferimento verrà invece associato a tale valore. Ciò garantisce che non si modifica effettivamente il valore originale this.

Un riferimento di tipo "CV1 T1" viene inizializzato da un'espressione di tipo "cv2 T2" come segue:

  • [...]

  • [...] oppure il riferimento deve essere un riferimento di valore.

    • Se l'espressione inizializzatore

      • è un xValue, classe prvalue, prvalue array o funzione Ivalue e [...], o

      • ha un tipo di classe (cioè, T2 è un tipo di classe), [...]

      poi [...]

    • Altrimenti, un temporaneo di tipo "cv1 T1" viene creato e inizializzato dall'espressione di inizializzazione utilizzando le regole per un inizializzazione della copia non di riferimento (8.5). Il riferimento è quindi legato al temporaneo. [...]

+0

Forse perché sei nel costruttore? –

+0

@KerrekSB Non vedo una regola che dice questo, ma ancora, perché dovrebbe fare il * puntatore * 'const'? –

+0

Hm, gratta quello ... ma nota che 'this' è un'espressione *, non una variabile. È un valore. –

Problemi correlati