2016-01-10 13 views
18

Ho il seguente costruttore:Perché le doppie parentesi graffe vuote {{}} creano una lista std :: initializer_list <double> con un elemento, non zero?

MyItem(std::initializer_list<double> l) { 
    std::cout << "l size " << l.size() << ")" << std::endl; 
} 

che si chiama più tardi con doppie parentesi graffe:

MyItem{{}} 

Il l.size risultato() dà è 1.

Qual è la meccanica dietro un simile comportamento?

Sembra che nidificato {} funzioni come un costruttore predefinito per l'unico elemento, ma non capisco perché e come funziona la deduzione dei tipi qui.

+1

Prendere in considerazione l'esistenza di uno stackover russo in http://ru.stackoverflow.com –

risposta

10

Quando si utilizzano le parentesi (inizializzazione dell'elenco) per inizializzare l'oggetto MyItem, il costruttore dell'elenco che si è mostrato è molto avido.

Questi passerebbero un elenco vuoto:

MyItem foo({}); 
MyItem foo{std::initializer_list<double>{}}; 

Questo passa un elenco contenente un unico elemento - un valore-inizializzato double (0.0):

MyItem foo{{}}; 

Questo funziona perché ci sono determinati contesti dove puoi semplicemente usare le parentesi al posto di un tipo conosciuto. Qui, sa di preferire il costruttore di lista che l'elenco dato dovrebbe contenere double.

Per completezza, sembra che passi una lista vuota, ma in realtà valore-inizializza foo se ha un costruttore predefinito (o in casi speciali, fa qualcosa di quasi equivalente). Se non esiste un costruttore predefinito, scegliere il costruttore dell'elenco, as shown here.

MyItem foo{}; 
+0

Come si deduce esattamente il tipo? {} Gioca il ruolo di costruttore predefinito? Non è specificato alcun tipo o 'auto'. Sono interessato ai meccanismi come i passi che il compilatore impiega per dedurlo. –

+1

@NikolayPolivanov, Questo potrebbe essere il contesto più difficile in cui le parentesi sono consentite in questo modo. In generale, sono permessi quando ripetete il tipo e il compilatore lo sa già. Ad esempio, hai 'void foo (string)'. Diciamo che vuoi passare i primi n caratteri di "abcde", dove n è una variabile. Normalmente faresti qualcosa come 'foo (string (" abcde ", n));'. Tuttavia, è ovviamente una stringa, quindi perché ripetere il tipo? 'foo ({" abcde ", n});' Quando si usa '{}', è tipicamente inizializzazione del valore, che di solito è 0 o il costruttore predefinito. 'foo ({});' passa una stringa vuota. – chris

+1

Anche in questo caso, il costruttore della lista è molto avido. Ad esempio, 'std :: string' ha un costruttore di liste che prende una lista di' char'. Se fai 'foo ({5, 'A'});', potresti aspettarti di ottenere una stringa con cinque caratteri A (AAAAA) perché c'è un costruttore per questo. Tuttavia, anche se 5 non è un 'char', è ancora convertibile in uno, nel senso che si ottiene effettivamente il personaggio con il valore 5 (probabilmente un personaggio di controllo), seguito da un singolo A. Ecco quanto sono avidi. La chiamata '(const char *, size_t)' funziona perché '" abcde "' non è convertibile in 'char'. – chris

5

Questa espressione

MyItem{{}} 

indicato conversione esplicita (la notazione funzionale).

Secondo Visual C++ (5.2.3 esplicita tipo di conversione (notazione funzionale))

  1. Analogamente, un semplice tipo-specificatore o typename-specificatore seguono a braced-init-list crea un oggetto temporaneo del tipo specificato direct-list-initialized (8.5.4) con l'elenco braced-init specificato, e il suo valore è quell'oggetto temporaneo come valore di prvalore.

Classe MyItem ha conversione di inizializzazione-list costruttore

MyItem(std::initializer_list<double> l) { 
    std::cout << "l size " << l.size() << ")" << std::endl; 
} 

che è stato selezionato per la conversione di tipo esplicita.Infatti è equivalente alla chiamata

MyItem({{}}); 

Quindi il costruttore ottiene una lista di inizializzazione con un elemento

{ {} } 

Un oggetto scalare di tipo double può essere inizializzato con un vuoto bretelle {}.

Come risultato l'espressione crea un oggetto temporaneo di tipo MyItem che viene inizializzato da un elenco di inizializzazione che contiene un elemento di tipo double che viene inizializzato dal valore mediante parentesi vuote.

Problemi correlati