什么是C++ 11可变参数模板中的va_arg()?

The*_*ask 6 c++ templates clang variadic-templates c++11

我已经阅读了一些关于这个新的C++ 11功能的文章,但是我并不了解所有的东西(我是C++的新手).如何在C中使用va_argfrom 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)

  • 我不推荐这个宏,因为它使用非C++ C99复合文字,而使用别名模板制作这个可移植的C++非常容易.@dyp这不是函数转换符号,因为它与语法`(type)expression`不匹配. - 约翰内斯绍布 (2认同)