13

受此答案的启发,我尝试了下一个示例:

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

并且编译失败并出现下一条错误消息(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> >'

我知道如何解决它:

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

但是为什么在上面的例子中编译失败了?

4

3 回答 3

24

因为地图是非聚合的,并且包含非聚合元素 ( std::pair<key_type, mapped_type>),所以它需要一个包含初始化列表的初始化列表,每对一个。

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

请记住,括号省略的规则适用于聚合,因此它们不适用于此处。

于 2012-07-31T14:41:23.203 回答
9

C++11 标准只允许在目标是聚合时省略大括号:

8.5.1 聚合 [dcl.init.aggr]

聚合是一个数组或类(第 9 条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等号初始化程序(9.2),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。

...

(第 11 段)

在表格声明中

T x = { a };

可以在初始化列表中省略大括号,如下所示。如果初始化器列表以左大括号开头,则后续的初始化器子句的逗号分隔列表初始化子聚合的成员;初始化子句比成员多是错误的。但是,如果子聚合的初始化器列表不以左大括号开头,则仅从列表中获取足够的初始化器子句来初始化子聚合的成员;任何剩余的初始化子句都被留下来初始化当前子聚合是其成员的聚合的下一个成员。

于 2012-07-31T14:52:42.593 回答
3

自从我完成 C++ 以来已经有很长时间了,但我的猜测是因为std::map期待一组单独的对象,每个对象都包含一个键和一个值对。

拥有单个项目的单个列表没有意义,而且也很难阅读(以确保您有许多项目可以完全被 2 整除)。

于 2012-07-31T14:41:52.973 回答