pla*_*cel 0 c++ templates variadic-functions variadic-templates
给出以下辅助函数
template <typename ... Ts>
auto f(Ts&& ... args) {}
template <typename T>
auto g(T x) { return x; }
Run Code Online (Sandbox Code Playgroud)
1)我们像往常一样扩展模板参数包.
template <typename ... Ts>
void test1(Ts&& ... args)
{
f(args...);
}
Run Code Online (Sandbox Code Playgroud)
2)这里扩展...发生在函数调用之后g().这也是合理的,因为g()每个人都会调用它args:
template <typename ... Ts>
void test2(Ts&& ... args)
{
f(g(args)...);
}
Run Code Online (Sandbox Code Playgroud)
3)我期望的逻辑相同test3(Is, args...)...,但没有.你必须写test3(Is..., args...):
template <typename ... Ts>
void test3(size_t i, Ts&& ... args)
{
f(args...);
}
template <typename ... Ts>
void test3(std::index_sequence<Is...>, Ts&& ... args)
{
// would expect test3(Is, args...)...;
test3(Is..., args...);
}
Run Code Online (Sandbox Code Playgroud)
我知道,我使用它,但是,我不明白.模板扩展的整个概念是表达式折叠的一种形式.不是以C++ 17的方式,而是...在关于可变参数的折叠(或重复,如果你喜欢)之前的子表达式的意义上.在test3情况下,我们"折叠"的表达test3(Is, args...)在相对于Is.然而,我们必须写test3(Is..., args...)而不是test3(Is, args...)....
有了这个标准的奇怪逻辑,你也可以写f(g(args...))而不是f(g(args)...)- 但这是无效的.看起来语言在不同的上下文中使用不同的逻辑.
不同语法背后的基本原理是什么?
在
test3情况下,我们"折叠"的表达test3(Is, args...)在相对于Is.然而,我们必须写test3(Is..., args...)而不是test3(Is, args...)....
这实际上是错误的.test3(Is..., args...)将扩展Is到位,然后args到位.因此呼叫test3(index_sequence<0,1,2>, x, y, z)最终会呼叫test3(0, 1, 2, x, y, z),这不是你想要发生的事情.你想要的test3(0, x, y, z); test3(1, x, y, z); test3(2, x, y, z);.
C++ 17调用它的方法是:
(test3(Is, args...), ...);
Run Code Online (Sandbox Code Playgroud)
这不是一个真正不同的语法.您有两个要以不同方式扩展的参数包:args在函数调用中及其Is周围,这意味着您有两个...s.逗号只是表明这些是单独语句的一种方式.
...放置的自由意味着您可以根据需要折叠它:
(test3(Is, args), ...); // test3(0,x); test3(1,y); test3(2,z);
(test3(Is..., args), ...); // test3(0,1,2,x); test3(0,1,2,y); test3(0,1,2,z);
test3(Is..., args...); // test3(0,1,2,x,y,z);
Run Code Online (Sandbox Code Playgroud)
有了这个标准的奇怪逻辑,你也可以写
f(g(args...))而不是f(g(args)...)- 但这是无效的
这不是奇怪的逻辑.那些意味着不同的东西 第一个扩展到f(g(a0, a1, a2, ..., aN))第二个扩展到f(g(a0), g(a1), g(a2), ..., g(aN)).有时你需要前者,有时你需要后者.拥有允许两者的语法非常重要.