防止 lambda 的返回类型扣除

prevent return type deduction of lambda

本文关键字:返回类型 lambda 防止      更新时间:2023-10-16

下面的代码由于从lambda返回的类型自动扣除而无法编译。

防止在 C++14 语法术语中没有尾随类型的这种推论的正确方法是什么?

编译错误是关于 test() 输入上的不兼容类型 (rvalue),它需要非常量引用

struct B {
int i;
};
struct A {
B &getB() { return b; }
private:
B b;
};
void test(B &b)  {
b.i++;
}
int main() {
A a;
test([&a]() { 
return a.getB();
});
return 0;
}

这里有两个问题。

首先,你

实际上并没有调用lambda,所以你没有将返回的值传递给test,而是传递函数对象,这显然是一个完全不兼容的类型!通过在 lambda 后添加()来调用它来解决此问题,从而将返回值传递给test()

[](){ return 42; } ();
//                 ^^ now the whole expression has value 42

其次,你是对的,推导出的返回类型将是B,而不是B&,并且临时对象可能不受test(B&)的引用到非const参数的约束。

解决此问题的一种方法是使用尾随返回类型来强制引用:

[&a]() -> B& { .... }

你似乎知道这一点,但不想这样做。为什么?

另一种选择是返回一个引用包装器,然后按值返回,但行为类似于引用:

return std::ref(a.getB()));

另一种选择是更改test以便能够接受一些临时。由于你需要它才能修改原始对象,你可以test一个指针,或者其他带有引用语义的类型(一个智能指针,一个std::reference_wrapper<B>,当你复制它时B有引用语义,...

void test(B* b) {
++(b->i);
}
...
test([&]() { return &a.getB(); } () );

学究注意:我知道++(b->i)中的括号不是绝对必要的。我发现它更清楚。