The*_*ask 6 c++ templates clang variadic-templates c++11
我已经阅读了一些关于这个新的C++ 11功能的文章,但是我并不了解所有的东西(我是C++的新手).如何在C中使用va_arg
from stdarg.h
来访问特定的参数?
template <typename ... Args>
void f(Args ... args)
{
for(size_t i = 0; i < sizeof ...(args); i++)
{
// obviously, args...[i] didn't work...
}
}
Run Code Online (Sandbox Code Playgroud)
Moo*_*uck 15
问题是TYPE var = args[c];
,你写的是TYPE
什么?每个i
都有不同的类型,因此您将无法使用这样的for
循环.
通常,正常的方法是使用递归.
void f() { } //end loop
template<class FirstType, typename...Args>
void f(FirstType&& first, Args&&...rest) {
//do loop body
loop_body(std::forward<FirstType>(first)...)
//do next "iteration"
f(std::forward<Args>(rest)...);
}
Run Code Online (Sandbox Code Playgroud)
还有这种方法可以在没有递归的情况下完成它,但它更高级:
template<typename...Args>
void f(Args&&...args) {
typedef int[] for_each;
for_each{((void)( loop_body(std::forward<Args>(args)) ),0)...,0};
}
Run Code Online (Sandbox Code Playgroud)
最后,如果你真的想通过索引访问一个:
//note that "i" must be a compile time constant
auto var = std::get<i>(std::tie(std::forward<Args>(args)...));
Run Code Online (Sandbox Code Playgroud)
typedef int[]
代码是很奇怪的,所以我会在这里打下了出来.loop_body(std::forward<Args>(args))...;
但不幸的是,参数包只能在某些上下文中扩展,而这不是其中之一.最简单和最明显的解决方案是将所有这些调用的结果传递给不执行任何操作的函数:do_nothing(loop_body(std::forward<Args>(args))...)
但不幸的是,这对void
返回类型失败,因为您无法实例化a void
传递给do_nothing
.更糟糕的是,它可能会以错误的顺序调用每个函数.将void
表达式"转换" 为其他东西的一种方法是使用逗号运算符,(func(), 0)
executaes func
然后"返回" 的神秘技巧0
.f(vs)...,0;
也没有(f(vs),0)...,0;
扩展参数包的有效背景.但是,type array[] = {vs...}
是一个有效的背景.所以现在我们有办法将这个上下文与带有返回值的表达式结合起来:int array[] = {(f(vs),0)...};
它可以工作!大多!int array[] = {(f(vs),0)..., 0};
.此外,大多数编译器都警告说这array
是一个未使用的变量.绕过该警告的一种方法是使类型成为临时类型. int a = (expr);
是一个本地的,但(int)(expr)
创建一个未命名的临时.所以我们想要(int []){(f(vs),0)..., 0};
.由于我无法回忆的原因,这(int[])
通常隐藏在typedef后面.作为最后的细节,由于某些类可以重载逗号运算符,因此最安全的是将函数转换为void
:int array[] = {((void)(f(vs)),0)..., 0};
不相关的,我在过去曾考虑过这个宏,它将丑陋的细节隐藏得更多一些.但我觉得我有一个缺点,我会忽视它,否则它会更常见.
#define FOREACH_VARIADIC(EXPR) (int[]){((void)(EXPR),0)...,0}
template<typename...Args>
void f(Args&&...args) {
FOREACH_VARIADIC(loop_body(std::forward<Args>(args)));
}
Run Code Online (Sandbox Code Playgroud)