为什么c ++从推断的返回类型中剥离引用限定符,以及为什么生命周期扩展不起作用?

时间:2018-01-04 20:08:14

标签: c++

给出以下代码:

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无法延长临时生命周期?

1 个答案:

答案 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的生命周期对象,因为这种情况不属于本部分标准中列出的任何例外情况。