2012-07-31 8 views
10

Inspirado por this answer, he intentado siguiente ejemplo:¿Por qué no se pueden omitir las llaves al inicializar el mapa?

#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; 
    } 
} 

y la compilación falló con el siguiente mensaje de error (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> >' 

Yo sé cómo solucionarlo:

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

pero ¿por qué la compilación falla en el ejemplo superior?

Respuesta

22

Como el mapa no es un agregado, y contiene elementos no agregados (std::pair<key_type, mapped_type>), por lo que requiere una lista de inicializadores llena de listas de inicializadores, una para cada par.

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 

Tenga en cuenta que las reglas para la elisión del refuerzo se aplican a los agregados, por lo que no se aplican aquí.

+0

'std :: pair' es un agregado, por lo tanto, no debería necesitar una lista de inicialización propia (como se explica en [la respuesta que he vinculado] (http://stackoverflow.com/a/ 11735045/476681). O, ¿estoy equivocado? –

+3

@ BЈовић en realidad, 'std :: pair' no es un agregado. No conozco las reglas para cuando' {} 'puede * omitirse *, pero en este caso no tendría sentido permitirlo. Quizás pueda decir más tarde ... – juanchopanza

+1

@ BЈовић mirando a §8.5, creo que la razón es que la elisión de abrazadera solo está permitida para tipos agregados. – juanchopanza

3

Ha pasado mucho tiempo desde que hice C++, pero supongo que es porque std::map está esperando un conjunto de objetos individuales, cada objeto contiene una clave y un par de valores.

Tener una sola lista de elementos individuales no tiene sentido, y también es difícil de leer (para asegurarse de que tiene un número de elementos que es exactamente divisible por dos).

8

El C++ 11 estándar permite llaves para ser elided sólo cuando el objetivo es un agregado:

8.5.1 Agregados [dcl.init.aggr]

Un agregado es una matriz o una clase (Cláusula 9) sin constructores proporcionados por el usuario (12.1), sin inicializadores ortográficos para miembros de datos no estáticos (9.2), sin miembros de datos no protegidos o privados no protegidos (Cláusula 11) , no hay clases base (Cláusula 10) ni funciones virtuales (10.3).

...

(párrafo 11)

En una declaración de la forma

T x = { a }; 

apoyos pueden ser elided en un inicializador-lista de la siguiente manera. Si la lista de inicializadores comienza con una llave izquierda, la siguiente lista de cláusulas de inicializador separadas por comas inicializa los miembros de a subaggregado; es erróneo que haya más cláusulas de inicializador que miembros. Sin embargo, si la lista de inicializador para un subagregado no comienza con un paréntesis izquierdo, entonces solo suficientes cláusulas de inicializador de la lista se toman para inicializar los miembros del subaggregado; cualquier cláusula de inicializador restante es a la izquierda para inicializar el siguiente miembro del agregado al cual pertenece el subaggregado actual .

+0

'std :: par' es un agregado, ¿o estoy equivocado? –

+2

@ BЈовић mal, no es un agregado. Tiene constructores y todo. – juanchopanza

+1

@ BЈовић: Pensé que la pregunta era sobre 'std :: map', pero neithe r 'pair' o' map' son agregados (tienen constructores proporcionados por el usuario). –

Cuestiones relacionadas