【问题标题】:Is va_list still used in C++? Or is it encouraged to use template<typename... T>?va_list 还在 C++ 中使用吗?还是鼓励使用 template<typename...T>?
【发布时间】:2018-02-04 01:54:43
【问题描述】:

在 C 中,定义可变长度参数的唯一方法是用省略号声明其原型,并使用 va_listva_startva_argva_end 提取它们。就像printf 系列和scanf 系列一样。

在 C++11 中,引入了一种新方法,如下所示。

template <typename T, typename... MoreT>
void func(T arg, MoreT... args){
    // Do some stuff
    func(args);
}

每种方法的优缺点是什么?在 C++ 中是不鼓励使用还是鼓励使用它们中的任何一个?

【问题讨论】:

  • 您为什么不花点时间了解可变参数的工作原理,然后您将能够更好地判断两种方法的相对指标。这将为您提供比 stackoverflow.com 上的简短答案更多的信息。

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


【解决方案1】:

c varadic 函数是特定于实现的,而且很可能是宏,因此它们没有类型安全性。更多信息。 varadic,例如

#define va_arg(list, mode) ((mode *)(list = (char *)list + sizeof(mode)))[-1]

作为开发人员,您必须为用户定义约定,完成所有这些步骤

va_list, va_start, va_arg, va_end.

另一方面,c++1x 提供了更多的工具来解决这个问题,例如使用类型特征,你可以检查它是否是整数,initializer_list 进行扩展等。所有这些你可以做很多强大的工作

【讨论】:

    【解决方案2】:

    可变参数函数没有很多好处,但有一些好处。

    如果您使用 C 可变参数函数,您将获得一个可以处理所有情况的编译函数。如果将 C++ 函数与可变参数模板一起使用,则每个参数组合都会获得一个编译函数。如果您的项目需要考虑代码大小,这可能是个问题。

    C++ 可变参数模板是类型安全的,而 C 可变参数函数则不是。这意味着编译器通常不会强制执行函数传递给可变参数函数的参数类型。 GCC 和 Clang 支持一些处理常见情况的属性:

    • __attribute__((format())) 告诉编译器可变参数使用printf/scanf 约定,并在参数与您传递的格式字符串不匹配时发出警告;
    • __attribute__((sentinel(N))) 告诉编译器最后一个可变参数应该是标记值。

    仍然很有可能搞砸。例如,open 函数是可变参数,需要在指定 O_CREAT 时将 mask 参数作为第三个参数,但它经常被遗忘,这些 __attribute__ 扩展都不能解决这个问题.

    标准允许但不强制实现允许将非 POD 类型传递给 C 可变参数函数;当它起作用时,语义是实现定义的。这意味着如果你希望你的代码是跨平台的,你不应该这样做。

    最后,学习如何正确使用 C++ 可变参数模板通常比学习如何使用 C 可变参数函数更难。

    【讨论】:

      【解决方案3】:

      C++ 力求比 C 更安全,例如nullptrenum class 提供更多类型安全的代码。编译器是您更聪明的朋友。

      可变参数模板允许您在 编译时 本身更具体地了解类型,而 va_list et.al 中的参数。 C 函数在运行时

      进行评估

      【讨论】:

        【解决方案4】:

        C 风格的可变参数函数在 C++ 中严重不鼓励。风格各不相同,但编写这些类型的函数会让你在某些圈子里(包括我的)陷入困境,除非有真正特殊的原因。

        就权衡而言,C 风格的可变参数函数完全是类型不安全的。您可以尝试从可变参数包中提取一些错误的类型,这将导致段错误。 C++ 可变参数模板是强类型的,所以这是不可能的(当然,除非你绝对用 reinterpret_cast 或类似的东西强制它)。

        除此之外,C++ 代码通常也会(由于代码膨胀而出现罕见的异常)在运行时执行得更好。编译器可以使用的间接更少,更多信息。但是,编译时间可能会更长,特别是因为可变参数模板函数(就像所有模板一样)通常必须在头文件中定义,而 C 风格的可变参数可以在 .cpp 文件中定义。

        在大多数 C 或 C++ 代码(为高性能应用程序编写)中,优先级的顺序通常是正确性,然后是性能,然后是编译时间。所以大多数 C++ 开发人员认为可变参数模板在这里是明确的赢家。

        这与 C++ 中使用模板的适当通用容器与 C++ 中基于 void* 的容器之间的比较基本上非常相似。类型安全 + 运行时性能与编译时性能(以及 .h 与 .cpp)。

        【讨论】:

        • 我有一个小问题。模板函数必须在头文件中定义吗?我不能在标题中声明它并在其他地方定义它(稍后将链接)吗?
        • @iBug:这是另一个问题,但大多数时候答案是否定的。但是,请阅读 templates 中的 extern
        • 如果只是弄乱可变参数中的类型总是会导致段错误......
        猜你喜欢
        • 1970-01-01
        • 2019-08-22
        • 2021-03-23
        • 1970-01-01
        • 2016-03-01
        • 2015-06-14
        • 1970-01-01
        • 1970-01-01
        • 2010-10-20
        相关资源
        最近更新 更多