C ++用于打印任意数量参数的函数

时间:2016-09-11 08:15:54

标签: c++ variadic-functions

我遇到过下面用C ++编写的这个函数。使用任意数量的参数调用函数trace()会以格式

的形式打印每个参数的值以及参数的名称

name1:value1 | name2:value2等等。

我想了解这段代码是如何工作的,以及双括号&&__VA_ARGS__等语法的含义。谢谢!

#define tr(...) trace(#__VA_ARGS__, __VA_ARGS__)

template <typename Arg1>
void trace(const char* name, Arg1&& arg1){
    cout << name << " : " << arg1 << endl;
}

template <typename Arg1, typename... Args>
void trace(const char* names, Arg1&& arg1, Args&&... args){
    const char* comma = strchr(names + 1, ',');
    cout.write(names, comma-names) << " : " << arg1 << " | " ; 

    trace(comma+1, args...);
}

2 个答案:

答案 0 :(得分:5)

PRCConfiguration

是一个接受可变数量参数的函数宏 它转发stringified版本作为第一个参数 没有使用预处理器就无法派生字符串表示。

评估示例:

#define tr(...) trace(#__VA_ARGS__, __VA_ARGS__)

解析为:

int main(){
    int i;
    float f;
    std::string s;
    tr(i,f,s);
}

两个可变参数模板函数展开每个参数并以递归方式调用自身。

结束递归的基本案例函数是:

int main(){
    int i;
    float f;
    std::string s;
    trace("i,f,s", i,f,s);
}

使用fold expression可以更干净地完成此操作。

&安培;&安培;用于允许完美转发。

答案 1 :(得分:0)

此功能取决于几种机制:

  • 可变参数模板:为了支持任意数量的参数,该函数被定义为可变参数模板。此功能具有递归语法,就像您在函数式语言中可以遇到的那样:template <typename Arg1, typename... Args>其中Arg1是第一个参数,Args是其余的。因此函数本身的递归定义 - 解包参数,它自己调用参数列表的尾部。注意comma-names技巧来计算参数名称的长度。
  • 预处理程序字符串化运算符__VA_ARGS__当然只是tr(...)(逗号分隔)参数列表的宏。在它之前添加#是从中创建字符串的内容,它作为trace(const char* names, ...)中的第一个参数传递。
  • 引用崩溃(Arg&amp;&amp; in the templates):这实际上是最复杂的事情,这很难过,因为它几乎没有任何东西。您可以逐字地删除&amp;&amp; s,代码仍然可以按预期工作。什么&amp;&amp;它是否调整预期参数的引用类型以匹配实际传递的参数,例如,如果通过引用传递参数,它将不会复制它,如果传递临时对象,它将使用移动语义。这个功能的实现技术谈论起来有点痛苦,所以here is another SO question for further reading