Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot bind non-const when trying to return reference to global from lambda

I'm trying to get a lambda to return a reference to global. My MCVE is

static int frob;

int& foo();

template <typename F>
auto bar(F f)
{
    return f();
}

int& foo()
{
    return bar([&](){
        return frob;
    });

    // int* p;
    // bar([&](){
    //     p = &frob;
    // });
    // return *p;
}

Using the outcommented implementation of foo passes compilation, but otherwise I get (from gcc 12.2.0)

error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’

I tried to create an int& inside foo to hold the reference to frob land (in hope that it would make the returned expression an int&), but that didn't help. Also moving frob into foo or even the lambda didn't help either, however it's not an alternative in my actual case anyway.

I'm a bit confused by the error so the question is first why do I get the error in the first place (and second how can I get around it, still transporting the result out of the lambda via return statement).

like image 490
skyking Avatar asked Apr 16 '26 09:04

skyking


1 Answers

auto is deduced to T, not T& in both bar and lambda's return type. auto& would be necessary.

So you either have to use auto& annotations

static int frob;

int& foo();

template <typename F>
auto& bar(F f)
{
    return f();
}

int& foo()
{
    return bar([&]() -> auto&{
        return frob;
    });

}

or, alternatively, if you do not care about their true return types, std::ref can do the trick as it can carry references using value semantics and "unpack" them by implicit conversion to T& whenever necessary.

#include <functional>
static int frob;

int& foo();

template <typename F>
auto bar(F f)
{
    return f();
}

int& foo()
{
    return bar([&](){
        return std::ref(frob);
    });

}
like image 156
Quimby Avatar answered Apr 18 '26 23:04

Quimby