笛卡尔积是多个集合所有可能的有序组合;C++标准库不提供现成函数,C++23的ranges::views::cartesian_product仅支持range类型(需将原始数组转为std::span或std::vector),手动递归实现需处理空输入、模板推导和类型适配。

笛卡尔积是什么,C++里没有现成函数
标准 C++ 库不提供直接计算多个数组笛卡尔积的函数,std::cartesian_product 是 C++23 的 ranges::views::cartesian_product,但仅限于 view 类型且要求所有输入是 range(比如 std::vector、数组视图),不能直接用于原始 C 风格数组(如 int arr[3])或混合类型。你得自己构造或适配。
用 ranges::views::cartesian_product(C++23)最简洁
前提是编译器支持 C++23 且启用了 std::ranges。它返回一个 lazy view,遍历时才生成每个元组,内存开销小,但注意:所有输入必须是可迭代的 range,且元素类型需支持结构化绑定。
-
int a[] = {1, 2};必须转成std::span(a)或std::vector才能传入 - 不能直接传
std::array的引用,要确保 lifetime 足够长(view 不拷贝数据) - 结果是
tuple-like元素,用结构化绑定解包:auto [x, y] = *it;
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v1 = {1, 2};
std::vector<char> v2 = {'a', 'b'};
for (auto [i, c] : std::views::cartesian_product(v1, v2)) {
std::cout << i << ',' << c << '\n';
}
}
手动实现通用递归版(C++17 及以上)
适用于任意数量的容器、任意类型、包括原始数组(只要包装成 range)。核心是递归展开维度,每层固定一个坐标,回溯推进。容易出错的地方是模板参数推导和空输入处理。
- 递归终止条件必须显式处理:当只剩一个容器时,直接输出每个元素作为单元素元组
- 用
std::apply+std::tuple组合各层结果,避免手动写 N 元 tuple 构造 - 若某输入为空,整个笛卡尔积为空 —— 很多手写版本漏掉这个逻辑
- 性能上,每次递归都复制中间结果,大数据量时建议改用迭代或预分配 vector
template <typename T, typename... Rest>
void cartesian_impl(const std::vector<T>& first,
const std::vector<Rest>&... rest,
std::vector<std::vector<int>>& out,
std::vector<int>& current) {
if constexpr (sizeof...(rest) == 0) {
for (const auto& x : first) {
current.push_back(x);
out.push_back(current);
current.pop_back();
}
} else {
for (const auto& x : first) {
current.push_back(x);
cartesian_impl(rest..., out, current);
current.pop_back();
}
}
}
原始数组怎么用?别裸传,先 wrap 成 span 或 vector
C 风格数组(int arr[N])不是 range,不能直接喂给 views::cartesian_product,也不能被模板自动推导为容器。常见错误是写 cartesian_product(arr1, arr2) 导致编译失败。
立即学习“C++免费学习笔记(深入)”;
- 推荐用
std::span<const int>(arr1, size)</const>—— 零拷贝、轻量、C++20 起可用 - 如果只支持 C++17,用
std::vector<int>{std::begin(arr1), std::end(arr1)}</int>,但有拷贝开销 - 切忌用
std::array的地址强转,会破坏类型安全和 lifetime
真正麻烦的不是算法本身,而是把“一堆不同长度、不同类型、混着原始数组和 vector”的输入统一成可迭代对象 —— 这步适配比笛卡尔积逻辑本身更花时间。


















