给出以下代码:
template <typename U> U func1(std::function<U()> func2) {
return func2();
}
const int x = 1;
const int& result1 = func1<const int&>([&x]() { return x; });
// result1 = ??????? (random garbage)
const int& result2 = [&x]() { return x; }();
// result2 = 1
默认情况下,lambda在推断返回值时从x的类型中剥离引用限定符似乎相当不方便,在这种情况下偷偷摸摸地导致对被破坏的临时值的引用。为什么这种语言功能以这种方式设计?
为什么result2有效,而result1无法延长临时生命周期?
答案 0 :(得分:1)
template <typename U>
U func1(std::function<U()> func2) {
return func2();
}
使用U = const int&
实例化此模板时,您会得到:
const int& func1(std::function<const int&()> func2) {
return func2();
}
然后,您将lambda [&x](){ return x; }
传递给func1
。
根据 8.1.5.4 Lambda表达式,lambda的返回类型推导为int
:
如果lambda表达式不包含lambda声明符,则为 如果lambda声明符是()。 lambda返回类型是auto, 它由trailing-return-type if指定的类型替换 提供和/或从中所述的退货声明中推断出来 10.1.7.4。
这意味着上面的func2
返回返回临时。
根据 15.2.6.2临时对象:
临时绑定到函数中返回值的生命周期 退货声明(9.6.3)未延期;临时被摧毁 在return语句中的完整表达式的末尾。
因此foo1
的返回值绑定到曾被销毁的临时值
return func2();
完成了。
在result2
的情况下,lambda仍会返回临时int
,但根据 15.2.6临时,临时的生命周期会延长到result2
的生命周期对象,因为这种情况不属于本部分标准中列出的任何例外情况。