Span 指一段连续的内存,例如一个数组;
template <typename T>
class Span {
public:
Span(T first, size_t s) ...;
Span(T first, T lasst) ...;
public:
// iterating underlying continuous memory;
begin() ...
end() ...
T & operator[](idx) ...
private:
T first;
T last;
};
loop 函数可以迭代所有通过的 span,就像嵌套的冒泡循环一样;
template <typename Func, typename ...Spans>
void loop(Func func, Spans &&...spans) {
// question: how to implements ?
}
例子
int main() {
int arr[] {1, 2, 3};
float arr2[] {1.1, 2.2};
int arr3[] {-1, -2, -3};
loop(func, Span(arr, 3), Span(arr2, 2));
/*
we can get:
func(1, 1.1);
func(1, 2.2);
func(2, 1.1);
func(2, 2.2);
func(3, 1.1);
func(3, 2.2);
*/
loop(func, Span(arr, 3), Span(arr2, 2), Span(arr3, 3));
/*
we can get:
func(1, 1.1, -1);
func(1, 1.1, -2);
func(1, 1.1, -3);
func(1, 2.2, -1);
func(1, 2.2, -2);
func(1, 2.2, -3);
func(2, 1.1, -1);
func(2, 1.1, -2);
...
*/
}
如何实现循环函数,使用c++语言特性到c++20都可以,但是没有标准库或者第三方库,只能手动实现;
没有递归函数调用,最好使用 for 循环;因为递归容易导致堆栈溢出;
使用向量和元组,结构绑定就可以了;
使用 C++23 后,这一点变得容易得多,因为
std::views::cartesian_product()
:戈德博尔
如果您仅限于 C++20,那么您必须自己做笛卡尔积 - 例如通过使用递归并将每个跨度的当前值绑定到函数:
戈德博尔
没有标准库实现:(如评论中所要求)
godbolt
您可以
ranges::for_each
与 C++23结合使用views::cartesian_product
,例如:这是对该帖子答案的简化,允许在编译时生成多个数组的笛卡尔积。
演示
主要思想是迭代一个
i
从 0 到 N-1 的整数(N 是笛卡尔积的可能条目数),然后从这个“全局”整数中检索idx
构成当前条目的每个数组的索引作为元组。然后,只需调用提供的函数fct
,参数是此索引上的折叠表达式idx
。它主要使用折叠表达式和
std::make_index_sequence
/std::index_sequence
。它还假定提供的数组支持operator[]
和size
方法。它适用于 c++17 及更高版本。
这里有一个替代方案,它使用一个数组来跟踪每个跨度的索引。索引数组被声明为具有
nSpans+1
元素,其中第一个元素用作标记。数组spanSizes
被声明为相同的大小,并且也有一个标记。变量carryIndex
跟踪应该增加哪个索引。这里的“进位”一词指的是索引以类似于加法中的进位的方式增加的事实。演示:https://godbolt.org/z/ejzhe7e5G(
main()
取自@Turtlefight 回答中的演示)