枚举一个包
Enumerating a pack
我不太理解 Daisy Hollman 演讲中的基本技巧:
https://youtu.be/15etE6WcvBY?t=2670
使用带有显式模板参数的 c++20 lamdas 枚举包。
#include <iostream>
#include <utility>
template <typename Function, typename ...Ts>
void enumerate_pack(Function f, Ts... args) {
[&]<std::size_t... Idxs>(std::index_sequence<Idxs...>) { (f(Idxs, args), ...); }
(std::make_index_sequence<sizeof...(args)>{});
}
int main() {
enumerate_pack([](std::size_t i, auto arg) { std::cout << i << ": " << arg << "\n"; }, "hello",
42, "world", 73.2);
}
我的问题是这部分:
(f(Idxs, args), ...);
在我看来,这就像我们“将 type 传递给函数”。好的,我们正在扩展包,所以它是单一类型而不是整个包,但在我看来它仍然是一个“类型”。更令人困惑的是,第二个参数 args
是局部变量的名称——同样是一个包,但仍然是一个变量。 args
的用法对我来说更有意义。
我原以为语法应该是:
[&]<std::size_t... Idxs>(std::index_sequence<Idxs...> idxs) { (f(idxs, args), ...); }
请注意,我现在已经为参数包 (idxs
) 命名并使用了它。这不会编译。
这里的语法是有点古怪,还是我遗漏了更深层次的东西?
这个
f(Idxs, args), ...
因为Idxs
和args
都是参数包,展开为:
f(0, args0), f(1,args1), .....
如果您将 Idxs
替换为 std::index_sequence<Idxs...>
那么它就不是一个包,它不会展开并且 f(std::index_sequence<Idxs...>, argX)
是 f
的错误签名。 f
没有以 std::index_sequence<Idxs...>
作为第一个参数的重载。
索引序列的唯一目的是让您掌握索引。不使用索引序列本身,因此不需要命名。
正在使用单个参数调用 lambda:
(std::make_index_sequence<sizeof...(args)>{})
如果您打开 std::make_index_sequence
的文档,它会解释它生成 std::index_sequence<0, 1, 2, 3>
,例如,如果 sizeof...(args)
是 4。
因此,在此示例中,lambda 的参数是 std::index_sequence<0, 1, 2, 3>
。
lambda 声明使用模板将 std::size_t... Idxs
推导为 0, 1, 2, 3
,并且每一个都被馈送,一次一个,以 f()
作为其第一个参数。对 f()
的调用同时扩展了两个参数包,这些函数的参数,以及从对 lambda 的调用中推导出来的参数。
我不太理解 Daisy Hollman 演讲中的基本技巧:
https://youtu.be/15etE6WcvBY?t=2670
使用带有显式模板参数的 c++20 lamdas 枚举包。
#include <iostream>
#include <utility>
template <typename Function, typename ...Ts>
void enumerate_pack(Function f, Ts... args) {
[&]<std::size_t... Idxs>(std::index_sequence<Idxs...>) { (f(Idxs, args), ...); }
(std::make_index_sequence<sizeof...(args)>{});
}
int main() {
enumerate_pack([](std::size_t i, auto arg) { std::cout << i << ": " << arg << "\n"; }, "hello",
42, "world", 73.2);
}
我的问题是这部分:
(f(Idxs, args), ...);
在我看来,这就像我们“将 type 传递给函数”。好的,我们正在扩展包,所以它是单一类型而不是整个包,但在我看来它仍然是一个“类型”。更令人困惑的是,第二个参数 args
是局部变量的名称——同样是一个包,但仍然是一个变量。 args
的用法对我来说更有意义。
我原以为语法应该是:
[&]<std::size_t... Idxs>(std::index_sequence<Idxs...> idxs) { (f(idxs, args), ...); }
请注意,我现在已经为参数包 (idxs
) 命名并使用了它。这不会编译。
这里的语法是有点古怪,还是我遗漏了更深层次的东西?
这个
f(Idxs, args), ...
因为Idxs
和args
都是参数包,展开为:
f(0, args0), f(1,args1), .....
如果您将 Idxs
替换为 std::index_sequence<Idxs...>
那么它就不是一个包,它不会展开并且 f(std::index_sequence<Idxs...>, argX)
是 f
的错误签名。 f
没有以 std::index_sequence<Idxs...>
作为第一个参数的重载。
索引序列的唯一目的是让您掌握索引。不使用索引序列本身,因此不需要命名。
正在使用单个参数调用 lambda:
(std::make_index_sequence<sizeof...(args)>{})
如果您打开 std::make_index_sequence
的文档,它会解释它生成 std::index_sequence<0, 1, 2, 3>
,例如,如果 sizeof...(args)
是 4。
因此,在此示例中,lambda 的参数是 std::index_sequence<0, 1, 2, 3>
。
lambda 声明使用模板将 std::size_t... Idxs
推导为 0, 1, 2, 3
,并且每一个都被馈送,一次一个,以 f()
作为其第一个参数。对 f()
的调用同时扩展了两个参数包,这些函数的参数,以及从对 lambda 的调用中推导出来的参数。