I have the following code to try to combine vectors by chaining a call to function combine
. I'm getting error: initial value of reference to non-const must be an lvalue
#include <algorithm>
using namespace std;
vector<int> combine(vector<int>& v1, vector<int>& v2) {
vector<int> v;
for(int ele : v1) v.push_back(ele);
for(int ele : v2) v.push_back(ele);
return v;
}
int main() {
vector<int> v1 = {1,2,3};
vector<int> v2 = {4,5,6};
vector<int> v3 = {7,8,9};
combine(v1, combine(v2, v3));
}
Why is this, and what is the correct workaround?
I am afraid that doing this might cause unnecessary copying:
vector<int> temp = combine(v2, v3);
combine(v1, temp);
CodePudding user response:
Your combine()
function is returning a vector
by value, which means it returns a temporary object that is destroyed as soon as the caller is done using it. As such, the function is returning an rvalue, and an rvalue cannot bind to a reference to a non-const object, as you are trying to do, hence the error.
Make your function parameters be references to const
objects instead. An rvalue can bind to a const
reference. And besides, your function is not modifying the input vector
s, so they should be const
anyway.
Try this:
#include <algorithm>
using namespace std;
// \/ \/
vector<int> combine(const vector<int>& v1, const vector<int>& v2) {
vector<int> v;
// you should add this for good measure:
// v.reserve(v1.size() v2.size());
for(int ele : v1) v.push_back(ele);
for(int ele : v2) v.push_back(ele);
// alternatively:
// v.insert(v.end(), v1.begin(), v1.end());
// v.insert(v.end(), v2.begin(), v2.end());
return v;
}
int main() {
vector<int> v1 = {1,2,3};
vector<int> v2 = {4,5,6};
vector<int> v3 = {7,8,9};
// now this will work as expected...
vector<int> v4 = combine(v1, combine(v2, v3));
for(int ele : v4) {
cout << ele << ' ';
}
}
Output:
1 2 3 4 5 6 7 8 9
CodePudding user response:
Making the arguments to combine
const solves the original problem:
vector<int> combine(const vector<int>& v1, const vector<int>& v2)
But having to call combine on pairs of vectors is both inefficient and too much to type. Here is my take on this:
#include <vector>
#include <concepts>
// make a variadic function so all the combining can be done in one call
template <typename T, typename... U>
requires (std::same_as<U , std::vector<T>> && ...) // all U must be vectors of T
std::vector<T> combine(std::vector<T>&& v, U... vs) { // allow move semantic for arguments
std::vector<T> res(v.size() (vs.size() ...)); // make vector big enough to hold the result
for(auto && ele : v) res.emplace_back(std::move(ele)); // copy/move first vector
([&res](auto && t) { // copy/move the rest
for(auto && ele : t) res.emplace_back(std::move(ele));
}(vs), ...);
return res; // return result with copy elision
}
int main() {
std::vector<int> v1 = {1,2,3};
std::vector<int> v2 = {4,5,6};
std::vector<int> v3 = {7,8,9};
std::vector<int> c = combine(v1, v2, v3);
}