2012-07-10 16 views
34

non capisco il motivo per cui le liste di inizializzazione non possono essere utilizzati sulla RHS di un operatore. Considerate:liste di inizializzazione e RHS degli operatori

class foo { }; 

struct bar 
{ 
    template<typename... T> 
    bar(T const&...) { } 
}; 

foo& operator<<(foo& f, bar const&) { return f; } 

int main() 
{ 
    foo baz; 
    baz << {1, -2, "foo", 4, 5}; 

    return 0; 
} 

L'ultima Clang (gcc così) si lamenta:

clang.cc:14:9: error: initializer list cannot be used on the right hand side of operator '<<' 
    baz << {1, -2, "foo", 4, 5}; 
    ^~~~~~~~~~~~~~~~~~~~~ 

    ^~~~~~~~~~~~~~~~ 

Perché sarebbe lo standard C++ non voglia questo? O in modo diverso, perché questo non va in contrasto con

baz << bar{1, -2, "foo", 4, 5}; 

?

+9

Perché tu non sia sovraccarico operatore '' << Per fare un 'initializer_list <>' sul RHS ... Qual è la tua domanda reale? – ildjarn

+0

Speravo che questo fosse equivalente a 'baz << bar {1, 2, 3, 4, 5};', ma sembra che non si sia verificata alcuna conversione. – mavam

+3

Se questo è il comportamento che vuoi, forse dovresti provare a dare a 'bar' un costruttore non esplicito che prende un singolo' initializer_list <> '. – ildjarn

risposta

45

Infatti, la versione finale di C++ 11 non consente l'utilizzo di elenchi di inizializzatori sul lato destro (o sul lato sinistro, peraltro) di un operatore binario.

In primo luogo, gli elenchi di inizializzatore non sono espressioni come definito al §5 della norma. Gli argomenti delle funzioni, nonché di operatori binari, in genere devono essere espressioni e la grammatica per le espressioni definite nel § 5 non include la sintassi per brace-init-list (vale a dire di inizializzazione-list puri di notare che il typename seguito da un tutore-init-elenco come bar {2,5,"hello",7} è espressione, però).

Per poter utilizzare puri inizializzazione liste convenientemente, lo standard definisce varie eccezioni, che sono riassunti nella seguente nota (non normativo):

§8.5.4/1 [...] Nota: 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 argumen funzione t (5.2.2)
- come pedice (5.2.1)
- come argomento per una chiamata costruttore (8.5, 5.2.3)
- come inizializzatore per un membro dati non statico (9.2)
- in un mem-inizializzatore (12.6.2)
- sul lato destro di una cessione (5.17)
[...]

il quarto punto sopra esplicitamente permette initializer- puro liste come argomenti di funzione (che è il motivo operator<<(baz, {1, -2, "foo", 4, 5}); opere), il quinto lo permette nelle espressioni pedice (vale a dire come argomento di operator[], ad es. mymap[{2,5,"hello"}] è legale), e l'ultima voce permette loro sul lato destro della assegnazioni (ma non operatori binari generali).

Non v'è alcuna tale eccezione per gli operatori binari come+, * o <<, quindi non si può mettere un lista di inizializzazione puro (vale a dire uno che non è preceduto da un TypeName) su entrambi i lati di esse.

Per quanto riguarda le ragioni di questo , un draft/discussion paper N2215 da Stroustrup e Dos Reis dal 2007 fornisce un sacco di comprensione molti dei problemi con inizializzazione liste in vari contesti.Nello specifico, esiste una sezione sugli operatori binari (sezione 6.2): ​​

Considerare usi più generali degli elenchi di inizializzatori. Per esempio:

v = v+{3,4}; 
v = {6,7}+v; 

Quando consideriamo operatori come zucchero sintattico per le funzioni, abbiamo naturalmente considerare quanto sopra equivale a

v = operator+(v,{3,4}); 
v = operator+({6,7},v); 

E 'quindi naturale per estendere l'uso delle liste di inizializzazione alle espressioni. Ci sono molti usi in cui le liste di inizializzatori combinate con gli operatori sono una notazione "naturale".
Tuttavia, non è banale scrivere una grammatica LR (1) che consente l'uso arbitrario di elenchi di inizializzatori. Un blocco inizia anche con un {consentendo così un elenco di inizializzazione come la prima entità (più a sinistra) di un'espressione porterebbe al caos nella grammatica.
È banale per consentire le liste di inizializzazione come operando destro di operatori binari, in indici, e parti isolate simili di grammatica. Il vero problema è consentire ;a={1,2}+b; come una dichiarazione di assegnazione senza consentire anche ;{1,2}+b;. Abbiamo il sospetto che permette inizializzatore elenca come a destra, ma non [sic] come argomenti a sinistra per la maggior parte degli operatori è troppo di un kludge, [...]

In altre parole, di inizializzazione-liste non sono abilitati sul lato destro perché non sono abilitati sul lato sinistro, e non sono abilitati sul lato sinistro perché questo avrebbe posto troppo grande una sfida per parser.

Mi chiedo se il problema potrebbe essere stato semplificato selezionando un simbolo diverso anziché le parentesi graffe per la sintassi dell'elenco inizializzatore.

+2

un simbolo diverso potrebbe aver reso possibile più cose, ma '' {} è un'estensione naturale dei quali inizializzatori di array e POD struct inizializzatori ereditato da C89. – aschepler

+1

Grazie per questa spiegazione - ho cercato per tenary operatore 'vero {1,2,3}: {4,5,6}' - quindi questo non è solo operatori binari problema ... – PiotrNycz

+1

@PiotrNycz Questo non può essere un? problema di analisi, ma un problema di deduzione tipo. Entrambe le alternative dell'operatore ternario devono concordare un tipo comune e qualcosa deve anche determinare la categoria del valore del risultato. Le parentesi oscurano il significato del programma. È meglio in '?:' Essere espliciti e mettere il nome-tipo prima di '{', e questo non sacrifica alcun potere espressivo. – Potatoswatter

Problemi correlati