我可以区分一个和多个参数吗?

时间:2013-10-08 16:50:30

标签: c++ c++11 printf variadic-functions

C ++ 11或C ++ 14中是否有任何新工具允许我们不再使用:

TRACE0("one-string-no-args");  

TRACE("formatting string with one-or-more args", arg1, arg2, etc);  

这些函数必须按名称区分,因为重载不能将零附加参数情况与一个或多个参数情况区分开来,据我所知。

这当然对printf样式接口很重要,它们能够知道不再有参数意味着你可以通过不尝试将格式化字符串解释为格式化字符串来避免一类错误,但是仅作为最终输出字符串。

3 个答案:

答案 0 :(得分:3)

您可能只是不知道该功能的名称:variadic templates

它的主要用途是从可变数量的参数中推导出可变数量的类型;你可以把它存储在某个地方(比如std::make_tuple()),或者只是打开参数来使用它们。

这是一个基本用法:

void print() {}

template<class Head, class... Tail>
void print(Head h, Tail... t)
{
    cout << h << endl;
    print(t...);
}

int main()
{
    print(3, "hello", 4.5);
}

在此处查看此行动:http://ideone.com/VA7YGK

正如您所看到的,它看起来像函数式编程(因为它是!),您可以将规则与参数列表分成头部和尾部,然后使用少一个元素调用自身。

另一个例子,从最近的一个问题,我以递归的方式定义了一个数据结构(简短而简单易读):Multikey map using variadic templates

std::thread构造函数是另一个例子,一旦它在生成的线程中开始运行,它需要一个可变数量的参数来将它们提供给函数;几乎C ++ 11中与函数交互的新内容(例如std::function)使用可变参数模板,因此它们可以接受任意类型的任意数量的参数。 std::tuplestd::make_tuple()std::tie()也会使用它。

在网上搜索,您会发现许多更高级的用法。特别注意参数扩展的规则,并完善转发。

答案 1 :(得分:0)

对于TRACE宏(通常包含在Microsoft的调试宏中),不,该语言将没有处理预处理器宏的“新”方法(它实际上与以前一样)。

对于一般的函数,一直支持可变函数(例如printf)。

答案 2 :(得分:0)

这对某些人来说可能看起来很愚蠢 - 但我有一公吨的C风格的printf代码需要维护。

我们可以使用boost的格式化库重建它们,也许我们可以在其中一天使用它。然而,与此同时,只要能够区分一个论点,或一个或一个或多个论点,就是向前迈出的一大步。

https://stackoverflow.com/users/365496/bames53注意到这样做是可行的,而且它似乎有效(在代码膨胀的某些可能费用中,并且需要注意的是,这仍然是printf并且存在所有陷阱)。

这是一个简单的例子,它在MFC / C ++中起作用:

bool Write(const wchar_t * pszText);
template <typename T> bool Write(const wchar_t * pszFormat, T, ...);

Write不需要(也不应该)调用vwsprintf等效,而Write&lt;&gt;这样做是为了在将输出字符串传递给Write之前构建输出字符串。

非常优雅。消除了只提供第二个接口的问题(如果你的一个字符串碰巧有一个意外的printf格式说明符,你就会遇到printf问题),或者强迫客户端指定Write()和WriteFormat()或类似地做在调用Write()之前在本地构造字符串。

这是写&lt;&gt;以Write:

的形式定义
template <typename T> bool SimpleTextFile::Write(const wchar_t * pszFormat, T, ...)
{
    va_list arglist;
    va_start(arglist, pszFormat);
    CStringW buffer;
    buffer.FormatV(pszFormat, arglist);
    va_end(arglist);
    return Write(buffer);
}