c++ - 是否可以在可变参数函数中处理非原始类型?

标签 c++ variables variadic-functions

我有同一个可变参数函数的两个版本,但是一个可以工作,另一个则不能。我怀疑原因是因为一个使用原始类型,而另一个使用 std::string。

void test1(int f_num, ...)
{
    va_list file_names;
    va_start(file_names, f_num);

    for(int i=0; i<f_num; i++)
    {
        string name = string(va_arg(file_names, char*));
        cout << name << endl;
    }
    va_end(file_names);
}

void test2(int f_num, ...)
{
    va_list file_names;
    va_start(file_names, f_num);

    for(int i=0; i<f_num; i++)
    {
        string name = va_arg(file_names, string);
        cout << name << endl;
    }
    va_end(file_names);
}

int main()
{
    test1(3, "Hallo", "you", "people");
    test2(3, "Hallo", "you", "people");
}

上面的结果如下:

Hallo
you
people
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

因此第一个函数可以工作,但第二个函数不能。我是否正确地假设这是因为可变参数宏不处理非原始类型?你能让它处理非原始类型吗?

最佳答案

va_arg 解码 va_list

您不能使用va_arg一次性转换传入的变量参数。 va_arg 的语法是解码变量参数以匹配传入的类型。例如,如果传入 int 值,则必须将其解码为带有 va_argint。如果您尝试将其解码为其他任何内容(例如,作为 double),则会导致未定义的行为。

由于您传入了字符串文字,因此类型应为 const char *

const char *arg = va_arg(file_names, const char *);
非平凡类上的

va_arg 是实现定义的

MSalter's answer清楚地解释了,即使您确实将 std::string 传递给需要变量参数的函数,它也不一定会起作用,因为语义是实现定义的。

When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.10). … Passing a potentially-evaluated argument of class type (Clause 9) having a non- trivial copy constructor, a non-trivial move contructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics. …
C++.11 §[expr.call] ¶7

注意:(18.10) 定义了 va_arg,并且(第 9 条)是 §[class]。

只需使用可变参数模板

您可以使用 C++11 的可变模板参数功能以类型安全的方式实现您想要的效果。假设您实际上想要做的不仅仅是打印每个参数,通常的模式是递归遍历参数包,一次解包一个参数。

void test3 (int f_num, std::string file_name) {
    std::cout << f_num << ':' << file_name << std::endl;
}

template <typename... T>
void test3 (int f_num, std::string file_name, T...rest) {
    test3(f_num, file_name);
    test3(f_num, rest...);
}

因此,迭代是通过递归调用函数来实现的,在下一次递归调用时将参数包减少一个参数。

关于c++ - 是否可以在可变参数函数中处理非原始类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50847671/

相关文章:

c++ - 自定义类型的 Qml 属性

c++ - 从文件读入后数组的第一个元素奇怪

c++ - 为什么两个迭代器在循环中分开?

C++ 变量数组

string - 如何删除 ksh 中字符串变量的最后一个字符?

c# - 如何将字符串转换为变量,vb6/c#/c++?

具有函数参数评估的 C++17 参数包扩展

java - 当重载编译器仅在存在 varargs 参数的情况下不喜欢 primitive 而不是 Object

c++ - 编译 Qt 应用程序以获得更好的调试信息 (Linux)

java - 结合 guava 的 ImmutableList 和 varargs