2012-07-31 7 views
10

Ispirato da this answer, ho provato il prossimo esempio:Perché non è possibile omettere le parentesi durante l'inizializzazione della mappa?

#include <map> 
#include <string> 
#include <iostream> 

int main() 
{ 
    const std::map< int, std::string > mapping = { 
     1, "ONE", 
     2, "TWO", 
    }; 

    const auto it = mapping.find(1); 
    if (mapping.end() != it) 
    { 
    std::cout << it->second << std::endl; 
    } 
    else 
    { 
    std::cout << "not found!" << std::endl; 
    } 
} 

e la compilazione non riuscita con il prossimo messaggio di errore (g ++ 4.6.1):

gh.cpp:11:5: error: could not convert '{1, "ONE", 2, "TWO"}' from '<brace-enclosed initializer list>' to 'const std::map<int, std::basic_string<char> >' 

So come risolvere il problema:

const std::map< int, std::string > mapping = { 
     {1, "ONE"}, 
     {2, "TWO"}, 
    }; 

ma perché la compilazione non riesce nell'esempio in alto?

risposta

22

Poiché la mappa non è un aggregato e contiene elementi non aggregati (std::pair<key_type, mapped_type>), è necessario un elenco di inizializzazione completo di elenchi di inizializzatori, uno per ogni coppia.

std::pair<int,int> p0{ 1,2 }; // single pair 
std::map<int, int> m { { 1,2 } }; // map with one element 
std::map<int, int> m { { 1,2 }, { 3,4} }; // map with two elements 

Tenete a mente che le regole per brace elisione applicabile agli aggregati, in modo che non si applicano qui.

+0

'std :: pair' è un aggregato, pertanto non dovrebbe richiedere un elenco di inizializzazione su di esso (come è spiegato in [la risposta che ho collegato] (http://stackoverflow.com/a/ 11735045/476681) o, mi sbaglio? –

+3

@ BЈовић in realtà, 'std :: pair' non è un aggregato.Non conosco le regole per quando' {} 'può essere * omesso *, ma in questo caso non avrebbe senso permetterlo. Potrei essere in grado di dire più tardi ... – juanchopanza

+1

@ BЈовић guardando §8.5, penso che il motivo è che l'elisione di rinforzo è consentita solo per i tipi aggregati. – juanchopanza

3

Sono passato molto tempo da quando ho eseguito C++, ma la mia ipotesi sarebbe perché std::map si aspetta un insieme di singoli oggetti, ogni oggetto contenente una chiave e una coppia di valori.

Avere un singolo elenco di singoli elementi non ha senso ed è anche difficile da leggere (per assicurarsi di avere un numero di elementi che è esattamente divisibile per due).

8

Il C++ 11 standard permette bretelle da elisa solo quando la porta è un aggregato:

8.5.1 Aggregati [dcl.init.aggr]

Un aggregato è una matrice o una classe (clausola 9) senza costruttori forniti dall'utente (12.1), senza inizializzatori di controventi o uguali per membri di dati non statici (9.2), nessun membro di dati non statici privato o protetto (clausola 11) , nessuna classe base (clausola 10) e nessuna funzione virtuale (10.3).

...

(Paragrafo 11)

In una dichiarazione della forma

T x = { a }; 

graffe possono essere tralasciata in un inizializzatore lista come segue. Se l'inizializzazione -elenco inizia con una doppietta a sinistra, poi il successivo elenco separato da virgole di inizializzazione-clausole inizializza i membri di un subaggregate; è errato perché non essere più inizializzazione-clausole rispetto ai membri. Se, tuttavia, l'inizializzazione-list per un subaggregate non inizia con una doppietta a sinistra, allora solo abbastanza inizializzazione-clausole della lista sono prese per inizializzare le membri del subaggregate; ogni residuo di inizializzazione-clausole sinistra per inizializzare il successivo membro della globale il cui corrente subaggregate è un membro.

+0

'std :: pair' è un aggregato, o sbaglio? –

+2

@ BЈовић sbagliato, non è un aggregato. Ha costruttori e tutto. – juanchopanza

+1

@ BЈовић: pensavo che la domanda riguardasse 'std :: map', ma neithe r 'pair' o' map' sono aggregati (hanno costruttori forniti dall'utente). –

Problemi correlati