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!
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.
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.
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&
).