如果返回了向量的一个项,lambda表达式的返回类型是什么
What is the return type of a lambda expression if an item of a vector is returned?
考虑以下片段:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
std::vector<int>v = {0,1,2,3,4,5,6};
std::function<const int&(int)> f = [&v](int i) { return v[i];};
std::function<const int&(int)> g = [&v](int i) -> const int& { return v[i];};
std::cout << f(3) << ' ' << g(3) << std::endl;
return 0;
}
我期待着同样的结果:在f
中,v
是通过const引用传递的,所以v[i]
应该具有const int&
类型。
然而,我得到的结果
0 3
如果我不使用std::函数,一切都很好:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
std::vector<int>v = {0,1,2,3,4,5,6};
auto f = [&v](int i) { return v[i];};
auto g = [&v](int i) -> const int& { return v[i];};
std::cout << f(3) << ' ' << g(3) << std::endl;
return 0;
}
输出:
3 3
因此我想知道:
在第二个片段中,lambda表达式
f
的返回类型是什么?f
和g
一样吗?在第一个片段中,构造
std::function f
时发生了什么,导致了错误?
lambda的返回类型使用auto
返回类型推导规则,该规则去除了引用。(最初,它使用了一组基于左值到右值转换的略有不同的规则(也删除了引用),但这被DR改变了。)
因此,[&v](int i) { return v[i];};
返回int
。因此,在std::function<const int&(int)> f = [&v](int i) { return v[i];};
中,调用f()
会返回一个悬空引用。将引用绑定到临时对象可以延长临时对象的生存期,但在这种情况下,绑定发生在std::function
的机器内部,因此当f()
返回时,临时对象已经不存在了。
g(3)
很好,因为返回的const int &
直接绑定到向量元素v[i]
,所以引用从不悬空。
如果返回向量的一项,lambda表达式的返回类型是什么?
这是个错误的问题。
您应该问,如果lambda表达式没有显式指定,那么它的返回类型是什么。
答案在C++11 5.1.2[expr.prim.lambda]第5段中给出,其中它说如果lambda没有return expr;
语句,它将返回void
,否则:
左值到右值转换(4.1)、数组到指针转换(4.2)和函数到指针转换后返回的表达式的类型(4.3);
(请参阅下面T.C.对DR 1048的评论,DR 1048略微更改了此规则,编译器实际上实现了更改后的规则,但在这种情况下无关紧要。)
左值到右值的转换意味着,如果return语句返回类似v[i]
的左值,则它衰减为右值,即按值仅返回int
。
因此,代码的问题是lambda返回一个临时的,但封装它的std::function<const int&(int)>
将引用绑定到该临时的。当你试图打印出临时值时,它已经消失了(它被绑定到一个不再存在的堆栈框架中的对象),所以你有未定义的行为。
修复方法是使用std::function<int(int)>
或确保lambda返回有效的引用,而不是右值。
在C++14中,非lambda也可以使用返回类型推导,例如:
auto f(std::vector<int>& v, int i) { return v[i]; }
这遵循与lambdas的C++11规则类似(但不完全相同)的规则,因此返回类型为int
。要返回您需要使用的参考:
decltype(auto) f(std::vector<int>& v, int i) { return v[i]; }
-
我假设第一个lambda可能返回
int
或int&
。不是const int&
,因为引用v
不是常量对象(捕获本身不可变并不重要,因为这是引用本身) -
当绑定到const-ref 时,临时性的生命周期会延长到封闭范围的末尾
我稍后会深入研究。现在,我用常规的推导直觉,说auto
会推导出int
,而auto&
会推断出int&
,所以我预计实际的返回类型是int
。如果有人打败我,那就更好了。我没有几个小时的时间
查看@menniumbug提供的测试:Live On Coliru
- 这 4 个 lambda 表达式之间有什么区别?
- 使用成员在类中创建 lambda 表达式
- 将 lambda 表达式传递给 std::function in C++
- 在 lambda 表达式中使用 std::atomic
- &&对lambda表达式有什么好处?
- Tbb 库:错误:编写自定义类函数而不是 lambda 表达式时,对函数的调用不匹配
- 列表.erase 中的 lambda 表达式
- 使用 lambda 表达式的 Raspbian G++ 8.3.0 导致 ']' 之前的预期主表达式 - 即使标准设置为 c++14
- 仅通过引用捕获的 lambda 表达式是否保证不会抛出?
- C++: priority_queue:模板参数中的 lambda 表达式
- 容器如何处理 lambda 表达式的参数
- 在C++ Lambda 表达式中,为什么人们更喜欢按值捕获而不是作为参数传递?
- 如何在 lambda 表达式中传递变量?
- 针对 std::function 的 lambda 表达式和模板推导:为什么会这样?
- 如何修改Lambda表达式以将输出放入文本文件
- C++如何使用lambda表达式来捕获上一次迭代的值
- 为什么Qt在信号和插槽中为lambda表达式抛出错误?
- C++:从捕获函数参数的函数返回 lambda 表达式
- C++ Lambda 表达式:通过 ref 开销捕获
- Qt 连接无法识别 lambda 表达式