迭代一个基于范围的临时 std::initializer_list for
Posted
技术标签:
【中文标题】迭代一个基于范围的临时 std::initializer_list for【英文标题】:Iterating over a temporary std::initializer_list with range based for 【发布时间】:2015-10-23 13:19:09 【问题描述】:鉴于此代码
#include <iostream>
#include <initializer_list>
#include <string>
int a, b;
int main()
for (auto p : std::initializer_list<std::pair<int &, std::string>>
a, "a" ,
b, "b" ,
)
std::cout << p.second << ": " << p.first << '\n';
我期待输出
a: 0
b: 0
和gcc 和clang 同意,但是,Visual Studio 2013 Update 5(我的版本,不确定 rextester 使用什么)不同意并打印:
: 0
: 0
Visual Studio 有一个 issue 和 std::initializer_list
,但它应该自更新 2 以来已修复。
这是 Visual Studio 中的错误还是我调用了未定义或未指定的行为?
【问题讨论】:
我相信这是一个错误,我当时在 connect 上报告了它,并且已经修复了,但我不记得是在更新还是在 2015 年。my test case from back then @NathanOliver 无法复制,适用于 2015 年。 @melak47 我不确定我做了什么,但我重新测试了它,它现在可以在我的机器上运行。我删除了我的误导性评论。谢谢:) 【参考方案1】:从cppreference 的“解释”部分,range-for 循环相当于:
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end;
++__begin)
range_declaration = *__begin;
loop_statement
您可以看到迭代范围 (range_epxression
) 绑定到转发引用。在你的情况下,后者变成了一个右值引用,因为你的 initializer_list
是一个临时的,因此它的生命周期被扩展到整个 for
循环。
MSVC 在这里错了。
【讨论】:
auto &&
实际上不是称为转发引用还是仅当它是模板时才称为转发引用?
@NathanOliver auto
行为类似于模板参数推导,所以确实是转发引用,谢谢:)【参考方案2】:
来自 cppreference.com:
在原始初始化列表对象的生命周期结束后,不能保证底层数组存在。 std::initializer_list 的存储是未指定的(即它可以是自动的、临时的或静态的只读内存,具体取决于情况)。 (直到 C++14)
底层数组是一个临时数组,其中每个元素都是从原始初始化列表的相应元素复制初始化的(除了缩小转换无效)。底层数组的生命周期与任何其他临时对象相同,只是从数组初始化一个 initializer_list 对象可以延长数组的生命周期,就像将引用绑定到临时对象一样(有相同的例外,例如初始化非-静态类成员)。底层数组可以分配在只读存储器中。 (C++14 起)
由此我推断编译器出错了,因为 initializer_list 的生命周期应该在右大括号之后结束。
【讨论】:
以上是关于迭代一个基于范围的临时 std::initializer_list for的主要内容,如果未能解决你的问题,请参考以下文章