防止lambda的返回类型扣除

ami*_*421 3 c++ auto return-type-deduction c++14

由于自动推导了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;
}
Run Code Online (Sandbox Code Playgroud)

BoB*_*ish 7

这里有两个问题。


首先,您实际上并未调用lambda,因此,您无需传递返回的值test,而是传递了函数对象,该对象显然是完全不兼容的类型!通过()在lambda之后添加来解决此问题,然后将返回值传递给test()

[](){ return 42; } ();
//                 ^^ now the whole expression has value 42
Run Code Online (Sandbox Code Playgroud)

其次,您是对的,推导的返回类型将B不是B&,并且临时对象可能不绑定到的ref-to-non- constargument test(B&)

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

    [&a]() -> B& { .... }
Run Code Online (Sandbox Code Playgroud)

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

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

return std::ref(a.getB()));
Run Code Online (Sandbox Code Playgroud)

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

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

给行人的注意事项:我知道++(b->i)绝对没有必要。我觉得更清楚。