C++数组的向量

30

为什么这个代码能够工作:

std::pair<int, int> p = {1,2};
std::vector<std::pair<int, int>> vp = { {1,2}, {3,4} };

但这不行吗?

std::array<int, 2> a = {1,2}; // still ok
std::vector<std::array<int, 2>> va = { {1,2}, {3,4} };

使用带有-std=c++0x编译选项的g++ 4.5.1版本,第二行代码失败并显示以下错误信息:

error: could not convert ‘{{1, 2}, {3, 4}}’ to ‘std::vector<std::array<int, 2u> >’

谢谢。


4
你能澄清一下 "fails" 的意思吗?(比如给出编译器的错误信息?) - Mat
哪个操作系统?可能是编译器的错误。 - BЈовић
@VJo @mat,已添加更多细节,谢谢! - andreabedini
1
我实际上怀疑gcc 4.5.1在这方面不是完全兼容的。 不幸的是,我不知道有哪个在线编译器可以帮助解决这个问题(ideone使用4.5.1)。 - Matthieu M.
2个回答

28
很不幸,std::array没有初始化列表构造函数。实际上,它根本就没有用户定义的构造函数——这个“特性”是C++03遗留下来的,因为省略所有用户定义的构造函数是启用C风格的大括号初始化的唯一方法。在我看来,这是当前标准中的一个缺陷。
那么为什么内置的大括号初始化在这种情况下不起作用呢?让我们看看std::array的内部实现:
template <typename T, int i> struct array {
    T data[i];
    // ...
}

好的,那么这是否意味着我们在初始化程序中需要使用双倍花括号(一对用于array,另一对用于data成员)?

std::array<int, 2> a = { {1, 2} };

C语言(以及C++)有一个关于花括号省略的特殊规则,允许省略内部的大括号,除非存在歧义。array利用了这个特性,使我们可以写出下面的代码:

std::array<int, 2> a = { 1, 2 };

因为花括号省略只允许在C风格的聚合初始化上下文中使用,如果涉及到更加复杂的内容,例如用户定义的初始化列表构造函数,则无法使用原始帖子中的示例。
尽管很丑陋,但以下内容应该可以工作:
std::vector<std::array<int, 2>> vp = { {{1,2}}, {{3,4}} };

在gcc 4.5和gcc 4.6上至少目前看来似乎不行,这让我觉得是编译器的一个bug。尽管如此,我并不完全确定。

这个问题有一定的相关性:如何使用初始化列表初始化成员数组?


1
жҲ‘зӣёеҪ“жҖҖз–‘std::arrayзңӢиө·жқҘжӣҙеғҸжҳҜtemplate <typename T, std::size_t i>гҖӮ - Chris Lutz
是的,您最后的例子应该可以工作。这是一个有意识并经过讨论的决定,不支持大括号省略语法用于除简单的 T t = { ... } 声明之外的任何情况。这也是为什么 return { ... } 不适用于 std::array<> 返回类型的原因。 - Johannes Schaub - litb
你最后的例子 std::vector<std::array<int, 2>> vp = { {{1,2}}, {{3,4}} }; 在 gcc 4.7.2 上可以运行。 - Ricky65

4

这是有效的:

std::vector<std::array<int, 2>> va = {
  std::array<int, 2>{1,2},
  std::array<int, 2>{3,4}
};

深入了解后,似乎std::pair有一个接受初始化列表的构造函数,但是std::array没有该功能:
std::pair<int, int> p ({1,2}) ;  // OK
std::array<int, 2> a ({1,2}) ;   // Invalid

但是现在我已经不懂了。

你实际上是让编译器推断花括号初始化列表中元素的类型。我想,问题就出在这里,但仍然不知道它是否符合标准。 - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接