Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can not omit braces when initializing map?

Inspired by this answer, I tried next example :

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

and the compilation failed with next error message (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> >'

I know how to fix it :

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

but why the compilation fails in the top example?

like image 656
BЈовић Avatar asked Jul 31 '12 14:07

BЈовић


3 Answers

Because the map is a non-aggregate, and contains non-aggregate elements (std::pair<key_type, mapped_type>), so it requires an initializer-list full of initializer-lists, one for each pair.

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

Bear in mind that the rules for brace elision apply to aggregates, so they do not apply here.

like image 143
juanchopanza Avatar answered Oct 13 '22 00:10

juanchopanza


The C++11 standard allows braces to be elided only when the target is an aggregate:

8.5.1 Aggregates [dcl.init.aggr]

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal- initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

...

(Paragraph 11)

In a declaration of the form

T x = { a };

braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a sub- aggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member.

like image 36
Michael Burr Avatar answered Oct 13 '22 01:10

Michael Burr


Been a long time since I've done C++, but my guess would be because std::map is expecting a set of individual objects, each object containing a key and a value pair.

Having a single list of individual items doesn't make sense, and it's also difficult to read (to make sure that you have a number of items that is exactly divisible by two).

like image 3
freefaller Avatar answered Oct 13 '22 01:10

freefaller