我有两个向量。我想遍历这两个元素的所有元素并做一些事情(比如将它们打印出来)。所以我可以这样写:
vector<int> vec_a{1, 2, 3}, vec_b{4, 5, 6, 7};
for (auto a : vec_a) {
cout << a;
}
for (auto b : vec_b) {
cout << b;
}
这有很多重复。我可以做类似的事情:
for (const auto& vec : {vec_a, vec_b}) {
for (auto elem : vec) {
cout << elem;
}
}
但这增加了一个额外的for
(虽然还不错,但我想知道是否还有更好的方法。
for (auto elem : concat(vec_a, vec_b)) {
cout << elem;
}
我知道我可以只合并向量(la Concatenating two std::vectors),但是语法甚至更笨拙(特别是因为我实际上有4个向量)。
我希望输出为:
1 2 3 4 5 6 7
答案 0 :(得分:11)
一个简单的解决方案是使用辅助函数:
#include <functional>
template <typename Func, typename... Containers>
void for_all(Func&& func, Containers&&... containers) {
auto iteration_func = [&](auto&& container) {
for (auto&& elem : std::forward<decltype(container)>(container)) {
std::invoke(func, std::forward<decltype(elem)>(elem));
}
};
(iteration_func(std::forward<Containers>(containers)), ...);
}
在这里,我们使用fold expression和立即调用的lambda来模拟可变参数模板参数上的循环,其中每个参数都被循环,并在其元素上调用提供的函数对象。
使用forwarding references和对std::forward
的调用会保留参数和元素的值类别,以与rvalue范围兼容(例如range-v3库中的move_view
)。 std::invoke
将功能对象的概念概括为pointers to members,这在某些情况下很有用。
示例:
int main() {
std::vector<int> vec_a{1, 2, 3};
std::vector<int> vec_b{4, 5, 6, 7};
for_all([](int n) {
std::cout << n << ' ';
}, vec_a, vec_b);
std::cout << '\n';
}
(wandbox)
可以混合使用不同的容器类型:
for_all([](const auto& n) {
std::cout << n << ' ';
}, std::vector{1, 2, 3}, std::list{"foo", "bar"});
答案 1 :(得分:1)
有一个不错的range library可以与C++14
一起使用,并且在很大程度上将成为C ++ 20的一部分。
该库中有ranges::views::concat
,它以干净的方式完全满足您的需求:
#include <iostream>
#include <ranges>
#include <vector>
#include <array>
#include <functional>
#include <range/v3/view/concat.hpp>
int main()
{
using ranges::views::concat;
auto a = std::vector<int>{ 1, 2, 6, 7 };
auto b = std::array<int , 2>{ 1, 3 };
auto c = { -1, -4, 7, 8, 9, 11};
for (auto x : concat(a, b)) {
std::cout << x << ", ";
}
std::cout << "\n--\n";
for (auto x : concat(c, a, b)) {
std::cout << x << ", ";
}
return 0;
}
可悲的是concat
在C ++ 20中不可用(在文档中找不到它,而gcc不支持它。)
答案 2 :(得分:0)
如果要减少 code ,只需编写一个函数即可迭代:
void iterate(const std::vector<int>& t)
{
for(auto i : t)
{
std::cout << i << ' ';
}
}
vector<int> a{1, 2, 3}, b{4, 5, 6};
iterate(a);
iterate(b);
编写该函数后,您可以改写上面L.F.的想法,并编写一个函数,该函数将对传递的任意数量的数组进行迭代:
template <class ... T>
void iterate_many(T ... args)
{
(void) std::initializer_list<int>{
((void) iterate(args), 0)...
};
}
这是完整的示例:
#include <iostream>
#include <vector>
using namespace std;
void iterate(const std::vector<int>& t)
{
for(auto i : t)
{
std::cout << i << ' ';
}
}
template <class ... T>
void iterate_many(T ... args)
{
(void) std::initializer_list<int>{
((void) iterate(args), 0)...
};
}
int main() {
vector<int> a{1, 2, 3}, b{4, 5, 6}, c{7, 8, 9};
iterate(a);
iterate(b);
std::cout << '\n';
iterate_many(a, b, c);
return 0;
}