Search code examples
c++c++14autoreturn-type-deduction

prevent return type deduction of lambda


The code below is not compilable due of auto deduction of the type returned from lambda.

what is a correct way to prevent this deduction in C++14 syntax terms without trailing type?

compilation error is about incompatible type (rvalue) on test() input which expects non-const reference

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;
}

Solution

  • There are two problems here.


    First, you don't actually call the lambda, so instead of passing the returned value into test, you pass the function object, which is clearly a completely incompatible type! Solve this by adding () after the lambda to call it, thereby passing the return value to test().

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

    Secondly, you are right, the deduced return type will be B, not B&, and the temporary object may not be bound to the ref-to-non-const argument of test(B&).

    One way around this would be to use a trailing return type to force a reference:

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

    You seem to know this, but don't want to do it. Why?

    Another option is to return a reference wrapper, which is then returned by value but behaves like a reference:

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

    Another option would be to change test to be able to accept some temporary. Since you need this to be able to modify the original object, you could have test take a pointer, or other type with reference semantics (a smart pointer, a std::reference_wrapper<B>, make B have reference semantics when you copy it, ...)

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

    Note for pedants: I know the parens in ++(b->i) aren't strictly necessary. I find it clearer.