Reputation: 246
Let's say we have this function, where vec1 and vec2 store the same kind of data:
int myFunc(vector<int>& vec1, vector<int>& vec2) {
for (auto const& elem : vec1) {
// do something
}
for (auto const& elem : vec2) {
// do the same thing
}
}
Clearly, duplicating code is not great. However, the following is not a solution:
int myFunc(vector<int>& vec1, vector<int>& vec2) {
for (auto const& vec : {vec1, vec2}) {
for (auto const& elem : vec) {
// do something
}
}
}
Doing so would result in a deep copy of vec1 and vec2, which is not what we want. I don't see a way to use pointers here as the vectors are passed in by reference (let's assume we can't change the function signature).
So how do we do the same thing to vec1 and vec2 without duplicating code?
Upvotes: 4
Views: 117
Reputation: 275350
Here are a number of different solutions:
Iterate over a std::initializer_list
of pointers, or std::reference_wrapper
s.
Write a lambda, containing either the body of the loop, or the whole loop. Call it twice manually.
Write foreach_arg(lambda, args...)
. Use it, passing a lambda that loops over the passed in vector.
Write the one-vector version as an independent function. Call it twice.
Write a variadic version. Put the loop in a lambda and comma-fold execute it.
Wrap each vector
in a std::span
, then make a std::initializer_list
of two spans, and go to town.
Write a ref-array class, wrap the two vectors in it, and go to town.
Use range-v3 to lazily concatenate the vectors and iterate over the concatenation.
Upvotes: 1
Reputation: 60218
One solution would be to write a small lambda that "does something", and then you don't have to repeat that code multiple times:
int myFunc(vector<int>& vec1, vector<int>& vec2)
{
auto do_something = [&](auto const & elem) {
// do something
}
for (auto const& elem : vec1) {
do_something(elem);
}
for (auto const& elem : vec2) {
do_something(elem);
}
}
If you can use the range-v3 library, you can write it like this:
int myFunc(vector<int>& vec1, vector<int>& vec2)
{
for (auto const& elem : ranges::views::concat(vec1, vec2)) {
// dosomething
}
}
Upvotes: 5
Reputation: 118300
It's fairly simple to use std::reference_wrapper
to avoid making a deep copy, and pretty much do the same thing what you wanted to do originally:
#include <iostream>
#include <functional>
#include <vector>
int myFunc(std::vector<int>& vec1, std::vector<int>& vec2) {
for (auto const& vec : {std::ref(vec1), std::ref(vec2)}) {
auto const &real_vec=vec.get();
for (auto const& elem : real_vec) {
}
}
return 0;
}
int main()
{
std::vector<int> vec1, vec2;
myFunc(vec1, vec2);
return 0;
}
No deep copies.
Upvotes: 5