过去几天我一直在玩C ++ 11,我想出了一些奇怪的东西。
如果我想统一初始化int:
int a{5};
但如果我对std :: vector做同样的事情:
std::vector<int> b{2};
不构造二元素数组,而是构造一个值为2的元素。似乎需要更明确地了解它:
std::vector<int> c{{2}};
std::vector<int> d = {2};
但不像b的声明 - 这似乎不一致。我已经看到了其他一些相同的效果。我要问的是 - 这是最终C ++ 11标准中的这种行为,还是只是在早期实施的草案中?如果是这样,为什么标准委员会会包含这种行为?看起来它破坏了统一初始化的整个目的,因为必须记住哪些类具有初始化列表构造函数,并且只使用旧的()语法而不是{}。或者一个人放弃统一初始化。
这似乎是一个很大的“陷阱”。但是我不知道它可能有优势。
编辑:此代码:
#include <iostream>
#include <vector>
int main() {
std::vector<int> a{2};
for (auto x: a) {
std::cout << x << std::endl;
}
return 0;
}
在gcc 4.6.2上输出“2”
答案 0 :(得分:22)
是的,根据§13.3.1.7按列表初始化初始化
,这种行为是有意的当非聚合类类型T的对象被列表初始化时 (8.5.4),重载决策分两个阶段选择构造函数:
- 最初,候选函数是初始化列表 类
T
的构造函数(8.5.4)和参数列表包含 初始化列表作为单个参数。- 如果没有可行性 找到初始化列表构造函数,重载解析是 再次执行,其中候选函数都是 类
T
的构造函数和参数列表包含 初始化列表的元素。
关于“统一初始化的整个目的”......“统一初始化”是一个营销术语,并不是一个很好的描述。该标准具有所有常规形式的初始化 plus 列表初始化,但没有“统一初始化”。列表初始化并不是初始化的最终形式,它只是实用程序带中的另一个工具。
答案 1 :(得分:6)
统一初始化并不意味着你的想法。添加它是为了使C ++中的类型之间的初始化更加统一。原因是:
typedef struct dog_ {
float height;
int weight;
} dog;
int main() {
dog Spot = { 25.6, 45};
dog Data[3] = { Spot, {6.5, 7} };
std::array<dog, 2> data = { { Spot, {6.5, 7} } }; //only in C++ obviously
return 0;
}
这是valid C and C++ code,而已经存在多年。 真的方便,但你必须记住,这只适用于POD类型。人们长时间抱怨没有办法std::vector<int> data = { 3, 7, 4, 1, 8};
,但有些类(std::array
)以奇怪的方式编写,以允许初始化列表构造函数。
因此对于C ++ 11,委员会做了这样的事情,我们可以让矢量和其他很酷的类也这样做。这使得所有类型的构造更加统一,因此我们可以使用{}
来初始化构造函数,也可以使用值列表。您遇到的问题是,std::initializer_list<int>
的构造函数重载是最佳匹配,并将首先选择。因此,std::vector<int> b{2};
并不意味着调用带有int
的构造函数,而是意味着从此vector
值列表中创建int
。从这个角度来看,它会创建一个包含单个值vector
的{{1}},这是完全合理的。要调用不同的构造函数,您必须使用2
语法,以便C ++知道您不想从列表初始化。
答案 2 :(得分:2)
标准规定初始化列表构造函数优先于其他构造函数。这只是一种情况,只能用()
替换{}
。还有其他一些,例如{}
初始化不允许缩小转换次数。