从初始化列表初始化,但没有{{{{{{{{{}}}}}}}}?

Joh*_*itb 24 c++ initializer-list c++11

我最近遇到了初始化列表的一些问题.考虑一个存储类似地图数据的程序

struct MyMapLike {
  MyMapLike(std::map<std::string, int> data)
    :data(std::move(data))
  { }

private:
  std::map<std::string, int> data;
};
Run Code Online (Sandbox Code Playgroud)

这看起来很直接.但是在初始化时,它会变得难看.我想让它看起来像

MyMapLike maps = { { "One", 1 }, { "Two", 2 } };
Run Code Online (Sandbox Code Playgroud)

但是编译器并不想接受这一点,因为上面意味着它应该寻找一个两个参数的构造函数,可以接受{ "One", 1 }{ "Two", 2 }分别.我需要添加额外的大括号,使它看起来像一个单参数构造函数接受{ { ... }, { ... } }

MyMapLike maps = { { { "One", 1 }, { "Two", 2 } } };
Run Code Online (Sandbox Code Playgroud)

我不想那样写.由于我有类似map的类,并且初始化程序具有映射列表的抽象值,因此我想使用前一版本,并且独立于任何此类实现细节,例如构造函数的嵌套级别.

一个解决方法是声明一个初始化列表构造函数

struct MyMapLike {
  MyMapLike(std::initializer_list< 
    std::map<std::string, int>::value_type
    > vals)
    :data(vals.begin(), vals.end())
  { }

  MyMapLike(std::map<std::string, int> data)
    :data(std::move(data))
  { }

private:
  std::map<std::string, int> data;
};
Run Code Online (Sandbox Code Playgroud)

现在我可以使用前者,因为当我有一个初始化列表构造函数时,整个初始化列表被视为一个元素而不是被分割成元素.但我认为构造函数的这种单独需求是死的.

我正在寻找指导:

  • 您如何看待前者和后者的初始化形式?在这种情况下需要额外的括号是否有意义?
  • 在这种情况下,您是否认为添加初始化列表构造函数的要求不好?

如果您同意我之前的初始化方式更好,您能想到什么解决方案?

GMa*_*ckG 10

由于我有类似地图的类,并且初始化程序具有映射列表的抽象值,我想使用以前的版本

而herin就是问题所在:由来提供构造函数,让你的类被视为地图.你把你的解决方案称为解决方案,但是没有什么可以解决的.:)

但我认为构造函数的这种单独需求是死的.

它是,但不幸的是,因为它是你的类,你必须指定初始化程序列表的工作方式.

  • 有时候我不知道.当我有一个带有'T`的构造函数的泛型类时,我不知道如何为它编写初始化列表构造函数:( (3认同)

bam*_*s53 6

您如何看待前者和后者的初始化形式?在这种情况下需要额外的括号是否有意义?

我认同.我认为允许构造函数调用不仅仅是在语法与构造函数匹配时,而是在语法与构造函数的单个参数的某个构造函数匹配时,以及依此类推.

struct A { int i; };
struct B { B(A) {}  B(int) {} };
struct C { C(B) {} };

C c{1};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您是否认为添加初始化列表构造函数的要求不好?

不.它可以让您获得所需的语法,但如果我们让编译器更难以使用构造函数,那么就不会产生问题.


Yli*_*sar 0

我同意这很丑。一旦我超出了非常简单的情况,我通常会废弃初始化列表,因为它们非常有限。对于你的情况,我会选择 boost::assign ,虽然不那么简洁,但可以提供更好的灵活性和控制。