Home > Net >  Cannot assign reference value to result of std::invoke
Cannot assign reference value to result of std::invoke

Time:06-16

I have a lambda that either appends an object and returns it or it returns an already existing object. On GCC, i receive the error:

cannot bind non-const lvalue reference of type 'T&' to an rvalue of type 'T'

Here is an example:

#include <iostream>
#include <cstdlib>
#include <functional>

struct foo {
    int a;
};

int main() {
    std::vector<foo> foos = {foo{22}};
    std::size_t new_index = -1;
    bool append = (rand() & 1) == 1;
    //compiler error in next line
    foo& new_foo = std::invoke([&foos,&new_index,append](){
        if(append) {
            new_index = foos.size();
            return foos.emplace_back();
        }else {
            new_index = 0;
            return foos[new_index];
        }
    });
    return new_foo.a;
}

In this example new_foo is supposed to be mutated after retrieving the object, hence const foo& new_foo is not an option.

CodePudding user response:

return type of lambda is not a reference by default, you have to specify it with trailling return type( -> foo&, -> decltype(auto)):

[&foos, &new_index, append]()-> foo& { /*..*/ }

or return a type which handles reference (as std::reference_wrapper):

[&foos,&new_index,append]() {
    if(append) {
        new_index = foos.size();
        return std::ref(foos.emplace_back());
    } else {
        new_index = 0;
        return std::ref(foos[new_index]);
    }
}

Demo

  • Related