如何迭代通过引用传递的几个对象



假设我们有这个函数,其中vec1和vec2存储相同类型的数据:

int myFunc(vector<int>& vec1, vector<int>& vec2) {
for (auto const& elem : vec1) {
// do something
}
for (auto const& elem : vec2) {
// do the same thing
}
}

显然,复制代码并不好。然而,以下不是解决方案:

int myFunc(vector<int>& vec1, vector<int>& vec2) {
for (auto const& vec : {vec1, vec2}) {
for (auto const& elem : vec) {
// do something
}
}
}

这样做会导致vec1和vec2的深度复制,这不是我们想要的。我看不出有什么方法可以在这里使用指针,因为向量是通过引用传递的(假设我们不能更改函数签名(。

那么,我们如何在不复制代码的情况下对vec1和vec2执行相同的操作呢?

使用std::reference_wrapper来避免深度复制非常简单,而且几乎可以做与最初想做的相同的事情:

#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;
}

没有深度复制。

一个解决方案是编写一个小lambda;做某事";,然后你不必多次重复该代码:

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);    
}
}

如果你可以使用range-v3库,你可以这样写:

int myFunc(vector<int>& vec1, vector<int>& vec2) 
{
for (auto const& elem : ranges::views::concat(vec1, vec2)) {
// dosomething    
}
}

这里有许多不同的解决方案:

  1. 在指针的std::initializer_liststd::reference_wrapper上迭代。

  2. 编写一个lambda,包含循环的主体或整个循环。手动调用两次。

  3. 写入foreach_arg(lambda, args...)。使用它,传递一个lambda,该lambda在传入的向量上循环。

  4. 将一个矢量版本写成一个独立的函数。打两次电话。

  5. 写一个可变版本。将循环放入lambda中,并用逗号折叠执行。

  6. 将每个vector包裹在一个std::span中,然后制作两个跨度的std::initializer_list,然后进城。

  7. 编写一个ref数组类,将两个向量封装在其中,然后进城。

  8. 使用range-v3对向量进行延迟连接,并对连接进行迭代。

最新更新