如何使用只有一个参考参数的可变长度参数列表?

Posted

技术标签:

【中文标题】如何使用只有一个参考参数的可变长度参数列表?【英文标题】:How to use variable length parameter list with only one reference parameter? 【发布时间】:2016-06-06 07:26:47 【问题描述】:

最近遇到一个烦人的问题,想定义这样的函数:

std::string my_sprintf(const char* format, ...)

    va_list args;
    va_start(args, format);
    ...

std::string my_sprintf(const std::string& format, ...)

    va_list args;
    va_start(args, format); // error
    ...

但是在使用变长参数列表时,似乎参考值不能是最后一个参数。

这是我可以让用户使用 std::string 作为格式字符串的一种方式吗?

也许检测 std::string 并将其转换为 c_str() 的因素或其他东西会起作用,但我不知道如何处理以下可变长度参数列表。

编辑: 我没有使用可变参数模板,因为我在里面使用了 vsprintf。也许避免使用 vsprintf 并使用 std::stringstream 是一种选择?

【问题讨论】:

c 不是 c++。 C++ 制作printf的方法是使用可变参数模板like here 为什么不使用可变参数模板呢? 【参考方案1】:

行为未定义:请参阅 C++ 标准 18.10/3(适用于 C++11 和 C++14)或cppreference.com: Variadic Arguments。

基本上,您只能将 C 中可用的类型与 va_start 一起使用,尽管 std::nullptr_t 类型有一个例外。

【讨论】:

它们也被称为 POD Plain Old Data,read this. 我很清楚这是被禁止的,但我只是想问有没有办法这样做。 不适用于va_start,没有。但是没有理由不能使用可变参数模板。或者只是深拷贝字符串。函数的 i/o 阶段将成为瓶颈,而不是深拷贝。 @Bathsheba 因为我在里面使用vsprintf,有没有更好的方法来避免使用它? 您应该指出您所指的 C++ 标准:在 C++14 标准中,有关 va_start() 的信息在 18.10/3 中。【参考方案2】:

在 C++ 中,传递 "unknown" 参数的方式是使用可变参数模板:

template <typename ... Ts>
std::string my_sprintf(const std::string& format, Ts&&...args)

    return my_sprintf(format.c_str(), std::forward<Ts>(args)...);

您使用const char* 的版本可能也应该是可变参数模板,使用sprintf 而不是vsprintf

【讨论】:

@user2079303:使用两个版本的可变参数,它都可以工作Demo。但实际上,使用省略号时,它是模棱两可的,需要进行一些重命名才能解决此问题。 @Jarod42 哦,对了。我试图在真空中理解这段代码 - 没有意识到有过载。抱歉吵了。

以上是关于如何使用只有一个参考参数的可变长度参数列表?的主要内容,如果未能解决你的问题,请参考以下文章

Java 我在学反射的时候,遇到可变长度参数列表,具体的成员方法就是?

Java可变参数

PHP 的可变长度参数 `...` 标记应该被称为啥?

如何让 argparse 识别跟随可变长度可选参数的位置参数?

C++ 从可变长度参数列表中提取 std::string

PHP:通过引用的可变长度参数列表?