5

我正在为 POD、STL 和像数组这样的复合类型开发小型(漂亮)打印机。在这样做的同时,我也在摆弄初始化列表并遇到以下声明

std::vector<double[3]> arr{ { 10, 11, 12 }, { 20, 21, 22 } }; 

似乎 VC2013 和 G++ 4.8 都不太满意,并发出一致的错误消息,在这两种情况下对我都不是很有帮助

对于 VC++: error C3074: an array can only be initialized with an initialize-list

对于 G++ 4.8: error: array must be initialized with a brace-enclosed initialize

所以要么初始化列表不能在这里使用,要么我的语法完全不正确?

在类似的方面,以下语法似乎是有效的

std::vector<std::array<int, 3>>  arr{ { 10, 11, 12 }, { 20, 21, 22 } };

我的初始化列表可能有什么问题?

  • 注意我知道我应该使用std::array而不是 C 类型的数组,但我只是在试验。
  • 注意如果你不想玩这个,这里有一个IDEONE版本
  • 注意另外,如果您可以将我推荐回标准,那将是非常有益的。
4

2 回答 2

5

阅读当前的 C++1y 草案标准

从表 99 之前开始:

T is EmplaceConstructible into X from args ,对于零个或多个参数 args ,意味着以下表达式是格式良好的:allocator_traits::construct(m, p, args)

表 100:

X(il);              |  Equivalent to      | X(il.begin(), il.end());
--------------------+---------------------+--------------------------------
X(i, j);            |                     | Requires:
X a(i, j);          |                     | T shall be EmplaceConstructible
                                          | into X from *i.

所以std::vector<double[3]> v{ {1,2,3}, {4,5,6} };有效的 iffdouble[3]EmplaceConstructiblefrom{1,2,3}作为初始化列表的一个元素被传递给 a std::vector<double[3]>

还有一个关于前向迭代器的子句,但这没问题(因为std::initialzier_list迭代器是前向迭代器)。

std::vector<T>接受一个std::initializer_list<T>参数。

std::initializer_list<double[3]>候选人名单也是如此。

首先,std::initializer_list<double[3]> x = {{1.0, 2.0, 3.0}};无法在 gcc 中编译。但假设这是 gcc 中的一个错误。

其次,::new (nullptr) double[3](std::initializer_list<double>{1.0, 2.0, 3.0});placement new无法编译,这EmplaceConstructable会导致缺少合适的覆盖。construct

所以double[3]不是EmplaceConstruble来自 astd::initalizer_list<double> 也不是来自 adouble[3]或其他任何东西(因为发生错误是因为我使用了一个括号,而不是因为括号中的内容,在放置 new 中),除非分配器做了我不知道的魔术来避免安置新。

因此,您的代码违反了当前的草案标准,可能违反了 C++11,当然还有 C++03(对容器有更严格的要求)。

于 2014-08-15T16:57:45.553 回答
3

这是 gcc 和 MSVC 中的错误;clang 可以正确编译您的代码。

最新版本的 gcc 实际上会使编译器崩溃(“ice”):

内部编译器错误:树检查:预期类“类型”,在 useless_type_conversion_p 中有“异常”(错误标记),位于 tree-ssa.c:1189

标准相当明确;来自[dcl.init.list]

5 - 类型的对象std::initializer_list<E>是从初始化列表构造的,就好像实现分配了一个N类型的元素数组E,其中N是初始化列表中的元素数。该数组的每个元素都使用初始值设定项列表的相应元素进行复制初始化,并且std::initializer_list<E>构造对象以引用该数组。[...]

改编该段中的示例:

using E = double[3];
using X = std::vector<E>;
E __a[2] = {{10, 11, 12}, {20, 21, 22}};
X x(__a, __a+2);

不过,这有点作弊。更接近的翻译会写E __a[2] = {E{10, 11, 12}, E{20, 21, 22}};,这是无效的。但当然可以从花括号初始化列表中复制初始化数组double[3]E __a0 = {10, 11, 12};

于 2014-08-15T17:01:29.287 回答