【发布时间】:2011-08-09 16:22:11
【问题描述】:
我最近偶然发现了初始化列表的一些问题。考虑一个存储类似地图的数据的程序
struct MyMapLike {
MyMapLike(std::map<std::string, int> data)
:data(std::move(data))
{ }
private:
std::map<std::string, int> data;
};
这看起来很简单。但是当初始化它时,它变得丑陋。我想让它看起来像
MyMapLike maps = { { "One", 1 }, { "Two", 2 } };
但是编译器不想接受这个,因为上面的意思是它应该寻找一个可以分别接受{ "One", 1 }和{ "Two", 2 }的双参数构造函数。我需要添加额外的大括号,使其看起来像一个接受{ { ... }, { ... } }的单参数构造函数@
MyMapLike maps = { { { "One", 1 }, { "Two", 2 } } };
我不想那样写。由于我有一个类似地图的类,并且初始化程序具有映射列表的抽象值,因此我想使用以前的版本,并且独立于任何此类实现细节,例如构造函数的嵌套级别。
一种解决方法是声明一个初始化列表构造函数
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;
};
现在我可以使用前者,因为当我有一个初始化列表构造函数时,整个初始化列表被视为一个元素,而不是被拆分为多个元素。但我认为构造函数的这种单独需求非常丑陋。
我正在寻求指导:
- 您如何看待前一种和后一种形式的初始化?在这种情况下需要额外的大括号是否有意义?
- 您认为在这种情况下添加初始化列表构造函数的要求不好吗?
如果你同意我的观点,前一种初始化方式更好,你能想到什么解决方案?
【问题讨论】:
-
@MooingDuck,我认为他就是这么做的!请参阅
::value_type。 -
“额外”的外部
{}的作用与内部的不同:它们是大括号初始化语法的一部分,表示正在调用构造函数,但 不是传递给构造函数的实际对象的一部分。同时,内部大括号指示映射的初始化列表的实际开始。我认为这是完全有道理的,事实上,Clang 警告最外层大括号的某些(合法)省略,所以我预计{{ /* ... stuff ... */ }}会随着时间的推移在喜欢大括号初始化语法的人中变得相当标准。
标签: c++ c++11 initializer-list