Error: cannot bind non-const lvalue reference of t

2019-08-07 03:11发布

问题:

I need to create a Bar object, which has a private object Foo f.

However, the value of Foo object parameter should be passed by the specific method int genValue().

If I initialize f in the constructor scope Bar(){...}, the compiler yell error, something like there is no constructor Foo().

If I construct like this Bar(): f(genValue()), the compiler yells the error:

test.cpp: In constructor ‘Bar::Bar()’:

test.cpp:16:19: error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’

Bar(): f(genValue()){
~~~~~~~~^~

test.cpp:7:2: note: initializing argument 1 of ‘Foo::Foo(int&)’
Foo(int &x) {
^~~

class Foo {
public:
    Foo(int &x) {
        this->x = x;
    }
private:
    int x;
};

class Bar {
public:
    Bar(): f(genValue()){
    }
private:
    Foo f;

    int genValue(){
        int x;
        // do something ...
        x = 1;
        return x;
    }
};

int main() {

    Bar bar ();

    return 0;
}

How can I fix the problem, if I don't want to modify Foo class and its argument value should be passed from genValue()? And, I don't want to use pure pointer (*), but a solution with smart pointer is okay!

回答1:

Your Foo type is garbage as written. This causes your error.

Foo(int &x) {
    this->x = x;
}

there is (a) absolutely no reason to take x by reference here, and (b) even less reason to take it by non-const reference.

Any of the following fix both Foo and your error.

Foo(int const&x) {
    this->x = x;
}
Foo(int const&x_in):x(x_in) {
}

Foo(int x) {
    this->x = x;
}
Foo(int x_in):x(x_in) {
}

and, if the value isn't actually an int yet is cheap-to-move:

Foo(int x) {
    this->x = std::move(x);
}
Foo(int x_in):x(std::move(x_in)) {
}

these are 6 independent solutions to your problem.

For an int I would use #4; for a non-int #6.

Fixing this outside of Foo is a bad idea, because you are getting the error because Foo was written wrong. The rest of your code is fine, avoid breaking good code.



回答2:

Don't pass int&, it can't be bound to a constant or temporary because those can't be modified - use const int& instead.

Actually for simple types you should prefer to pass by value instead, and let the optimizer worry about providing the best implementation.



回答3:

A non-const reference parameter, such as an int&, can only refer to an "lvalue," which is a named variable.

auto takes_nonconst_reference = [](int&){};
auto takes_const_reference = [](const int&){};
auto takes_value = [](int){};
auto returns_int = []{return 42;};

int foo = 1;

// OK
takes_nonconst_reference(foo);
takes_const_reference(foo);
takes_const_reference(returns_int());
takes_value(foo);
takes_value(returns_int());

// compilation error, value returned from a function is not a named variable
takes_nonconst_reference(returns_int());

In this particular case, since your class is storing a copy of the constructor parameter, you should pass it by value (int, not int& nor const int&).