防止 return lambda 的类型推导

prevent return type deduction of lambda

由于自动推导从 lambda 返回的类型,以下代码无法编译。

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

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

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,因此您没有将 returned 值传递给 test,而是传递函数对象,这显然是一个完全不兼容的类型!通过在 lambda 后面添加 () 来解决这个问题,从而将 return 值传递给 test().

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

其次,你是对的,推导的 return 类型将是 B,而不是 B&,并且临时对象可能不会绑定到 ref-to-non- const test(B&) 的参数。

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

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

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

另一种选择是 return 引用包装器,然后按值 return 编辑但表现得像引用:

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

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

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

书呆子注意事项:我知道 ++(b->i) 中的括号不是绝对必要的。我觉得更清楚了。