2013-04-23 15 views
32

vedere questo esempio:Perché è possibile utilizzare operator = ma non operator == con gli inizializzatori di bretelle C++ 11?

struct Foo 
{ 
    int a; 
    int b; 

    bool operator == (const Foo & x) 
    { 
     return a == x.a && b == x.b; 
    } 
}; 

int main() 
{ 
    Foo a; 

    a = {1, 2}; 

    if (a == {1, 2}) // error: expected primary-expression before ‘{’ token 
    { 
    } 
} 

La linea a={1,2} va bene. Le parentesi graffe vengono convertite in un Foo in modo che corrisponda al tipo di argomento del metodo implicito operator=. Funziona ancora se operator= è definito dall'utente.

La riga if (a=={1,2}}) errori come indicato.

Perché l'espressione {1,2} non viene convertita in un Foo in modo che corrisponda al metodo definito dall'utente operator==?

+0

Questo è con g ++ - 4.7. – spraff

+0

Non vedo alcun operatore esplicito == 'nel codice. Intendevi "definito dall'utente"? –

+2

il fatto che sia chiamato elenco di inizializzazione piuttosto che litterale dell'espressione potrebbe essere un indizio del fatto che non è supportato di proposito (anche se non ci ho pensato prima di chiederlo). – didierc

risposta

41

L'inizializzazione dell'elenco non può essere utilizzato come argomento per un operatore nel caso generale. Per Paragrafo 8.5.4/1 della C++ 11 standard:

[...] List-inizializzazione può essere utilizzato

- come l'inizializzazione in una definizione della variabile (8.5)

- come l'inizializzazione in una nuova espressione (5.3.4)

- in una dichiarazione di ritorno (6.6.3)

- come per la gamma-inizializzatore (6,5)

- come funzione argomento (5.2.2)

- come pedice (5.2.1)

- come argomento di un costruttore di invocazione (8.5, 5.2.3)

- come inizializzatore di un membro di dati non statico (9,2)

- in una mem-inizializzatore (12.6.2)

- sul lato destro di un asino ignment (5,17)

L'ultimo elemento spiega perché elenco inizializzazione è consentito sul lato destro della operator =, anche se non è consentito in generale per un operatore arbitrario.

A causa della quinta voce sopra, tuttavia, può essere usato come argomento di una chiamata di funzione normale, in questo modo:

if (a.operator == ({1, 2})) 
+0

Perché l'incarico funziona allora? – 6502

+4

@ 6502: Perché lo standard dice così (vedi il paragrafo che ho citato) –

+0

Certo ... ma la domanda interessante è PERCHE 'lo dice. – 6502

7

E 'semplicemente non supportato.

liste

Initializer sono esplicitamente definiti di essere valido in inizializzazioni ([C++11: 8.5.4]), e assegnazioni:

[C++11: 5.17/9]: A rinforzato-init-list può apparire sul lato destro della

  • un'assegnazione a uno scalare, nel qual caso l'elenco di inizializzazione deve avere al massimo un singolo elemento. Il significato di x={v}, dove T è il tipo scalare dell'espressione x, è quello di x=T(v) tranne che non è consentita la conversione di restringimento (8.5.4). Il significato di x={} è x=T().
  • un'assegnazione definita da un operatore di assegnazione definito dall'utente, nel qual caso l'elenco di inizializzatori viene passato come argomento della funzione operatore.

Non esiste un testo standard per consentire altri casi arbitrari.

Se fosse consentito, in questo esempio, il tipo di {1,2} sarebbe abbastanza ambiguo. Sarebbe una caratteristica linguistica complicata da implementare.

+1

Qual è la principale differenza logica tra 'operator =' e 'operator =='? Entrambi possono assumere tipi arbitrari come RHS – 6502

+0

Immagino che trattino l'assegnazione come un caso speciale a causa delle sue somiglianze con l'inizializzazione. –

+1

Suppongo che possa essere definito per avere qualsiasi tipo di contesto richiesto dall'istruzione. Dobbiamo già decidere se un numero è un int, float o argomento per un costruttore, ecc. Avere '{1,2}' da solo non ha alcun significato. – spraff

4

È richiesto un cast esplicito.

if (a == (Foo){1, 2}) 
{ 
} 
+4

Funziona, oppure puoi lasciare il '()'; 'a == Foo {1,2}' – bames53

0

Quando si utilizza l'espressione contenente il tipo definito dall'utente e un operatore == overload funzione operatore viene chiamata che secondo definizione hai dato richiede un argomento di un riferimento di un oggetto della classe Foo

così la vostra espressione dovrebbe essere come a == b

dove b è un oggetto della classe Foo

Qui con questa espressione si sarà in grado di confrontare i dati membro di B e a e, quindi, sapere se sono uguali o meno

0

Nessun motivo reale.

C++ è il risultato di uno sforzo del comitato, quindi a volte possono accadere strane ma deliberate decisioni a causa di complesse dinamiche politico/sociologiche.

La sintassi del C++ è difficile. Molto difficile. Quasi incredibilmente difficile. Ci sono anche regole come "se puoi analizzare questa sequenza arbitrariamente lunga di token come sia questo o quello, allora è questo".

Ci sono voluti molti anni prima che i compilatori concordassero semplicemente su cos'è il C++ e cosa no.

In questo caso il mio indovinare è che a loro non piaceva l'idea che i casi che sembrava molto simile:

MyClass x = {...}; 
MyClass y; y = {...}; 

verrebbero gestite in modo diverso per cui v'è una disposizione speciale per l'assegnazione per consentire la sintassi.

Da un punto di vista tecnico non vedo quali siano i problemi di consentirlo anche per altri operatori, e d'altra parte se ci sono problemi (ad es. Sovraccarico, tempificazione dei template ecc.) Non lo faccio vedi come il compito può sperare di sfuggirgli.

EDIT

g ++ permette di utilizzare non solo rigorosa operator= ma anche operator+=, operator-= e simili "assegnazione aumentata". I problemi logici possono verificarsi solo se si autorizzano sovraccarichi non membri (che sono vietati per gli operatori di assegnazione e di assegnazione aumentata).