如何用std::views::cartesian_product重复同一向量N次?
如何通过指定重复次数实现std::vector的笛卡尔积?
以下代码实现了std::vector{1,2,3}的三次笛卡尔积并输出结果:
#include <iostream> #include <ranges> #include <vector> int main() { const auto y = std::vector{1, 2, 3}; for (int i{1}; auto const &[a, b, c] : std::views::cartesian_product(y, y, y)) std::cout << "(" << a << ' ' << b << ' ' << c << ")" << (i++ % 3 ? " " : "\n"); }
编译运行后输出:
$ g++-12-master --std=c++23 cartesian.cpp -o cartesian.exe && ./cartesian.exe (1 1 1) (1 1 2) (1 1 3) (1 2 1) (1 2 2) (1 2 3) (1 3 1) (1 3 2) (1 3 3) (2 1 1) (2 1 2) (2 1 3) (2 2 1) (2 2 2) (2 2 3) (2 3 1) (2 3 2) (2 3 3) (3 1 1) (3 1 2) (3 1 3) (3 2 1) (3 2 2) (3 2 3) (3 3 1) (3 3 2) (3 3 3)
问题:能否只传入一次向量,通过指定重复次数(比如3次)实现相同效果?
C++23标准中的std::views::cartesian_product本身不支持直接传入重复次数参数,但可以通过模板元编程实现这个需求,避免重复书写向量参数:
实现方案:编译期指定重复次数的模板函数
#include <iostream> #include <ranges> #include <vector> #include <utility> #include <tuple> // 生成N次重复的笛卡尔积视图 template <std::size_t N, typename Range> auto repeated_cartesian(Range&& r) { // 利用索引序列展开参数包 auto make_product = []<std::size_t... Idx>(Range&& range, std::index_sequence<Idx...>) { // 忽略索引值,重复传入range N次 return std::views::cartesian_product((static_cast<void>(Idx), std::forward<Range>(range))...); }; return make_product(std::forward<Range>(r), std::make_index_sequence<N>()); } int main() { const auto y = std::vector{1, 2, 3}; int i = 1; // 调用时指定重复次数3 for (const auto& elem_tuple : repeated_cartesian<3>(y)) { std::cout << "("; // 遍历元组内的元素 std::apply([&](const auto&... elems) { ((std::cout << elems << ' '), ...); }, elem_tuple); // 处理输出格式,移除最后一个空格 std::cout << "\b)" << (i++ % 3 ? " " : "\n"); } }
说明
- 这个模板函数
repeated_cartesian<N>通过std::index_sequence生成编译期的整数序列,展开时重复传入目标向量N次,最终调用std::views::cartesian_product生成笛卡尔积视图。 - 代码依赖C23特性,需要用支持C23的编译器(如GCC 12+、Clang 15+)编译。
- 如果需要运行时指定重复次数,可以实现递归的自定义视图,但编译期指定的方式性能更优。
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

