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

What's va_arg() in C++11 variadic template?

本文关键字:arg 是什么 va 变参 参数 C++11      更新时间:2023-10-16

我读过一些关于这个新的C++11特性的文章,但我并没有完全理解(我是C++的新手)。如何访问特定的参数,就像在C中使用stdarg.h中的va_arg一样?

template <typename ... Args>
void f(Args ... args)
{
    for(size_t i = 0; i < sizeof ...(args); i++)
    {
        // obviously, args...[i] didn't work...
    }
}

问题是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)...);
}

还有一种不用递归的方法,但它更高级:

template<typename...Args> 
void f(Args&&...args) {  
    typedef int[] for_each;
    for_each{((void)(   loop_body(std::forward<Args>(args))  ),0)...,0};
}

最后,如果你真的想通过索引访问一个:

//note that "i" must be a compile time constant
auto var = std::get<i>(std::tie(std::forward<Args>(args)...));


typedef int[]代码非常奇怪,所以我将把它放在这里
我们想调用函数loop_body(std::forward<Args>(args))...;,但不幸的是,参数包只能在某些上下文中扩展,而这不是其中之一。最简单、最明显的解决方案是将所有这些调用的结果传递给一个什么都不做的函数:do_nothing(loop_body(std::forward<Args>(args))...),但不幸的是,这对于void返回类型来说失败了,因为您无法实例化一个void来传递给do_nothing。更糟糕的是,它可能会以错误的顺序调用每个函数。将void表达式"转换"为其他表达式的一种方法是使用逗号运算符,(func(), 0)执行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)));
}

接受的答案非常好,但这里有一个使用C++14通用lambdas:的想法

template <typename F>
void variadic_for_each(F) {}
template <typename F, typename Head, typename... Tail>
void variadic_for_each(Head&& head, Tail&&... tail, F f)
{
    f(std::forward<Head>(head));
    variadic_for_each(std::forward<Tail>(tail)..., f);
}

示例用法:

template <typename... Ts>
void myFunc(Ts&&... vs)
{
    variadic_for_each(std::forward<Ts>(vs)..., [](auto&& v)
    {
        // loop body
    });
}