【问题标题】:Passing Variable Number of Arguments with different type - C++传递具有不同类型的可变数量的参数 - C++
【发布时间】:2011-04-03 02:31:21
【问题描述】:

我正在使用 C++ 进行编码,并且有几个关于省略号的问题:

  1. 是否可以将类或类指针传入省略号?

  2. 基本上我想要做的是传入char* 和class 类型的可变数量的参数。我目前正在使用省略号并试图弄清楚如何通过课程。如果省略号在这里不适用,有哪些可用选项?

我想让用户直接使用func( params 1, params2, ...) 调用函数,而无需先将参数显式分配到向量或数组中,然后再将向量或数组作为参数传递给函数。

【问题讨论】:

  • 除非您必须模仿现有 API 的显式语法,否则我会避免使用省略号。正如 tenfour 的回复所暗示的,更喜欢链接或流式传输,或重载。
  • tenfour 建议也使用std::vector!
  • 你将如何构建一个任意的、未知的类型的vector?

标签: c++


【解决方案1】:

您应该考虑到使用可变参数函数(C 风格)是一个危险的缺陷。 如果传递给函数的对象与等待的类型不匹配,或者如果你没有输入确切数量的等待参数,那么你基本上会在运行时发生剧烈的崩溃。

在 Bjarne Stroustrup C++ 深度系列 - C++ 编码标准 - Herb Sutter 和 Andrei Alexandrescu 的 101 条规则、指南和最佳实践中,第 98 章:不要使用可变参数(省略号)

我非常赞同@tenfour 的提议:

  • 使用包含所有参数的std::vector。

【讨论】:

  • 其他人可能会反对,但这显然是线程中最好的建议。需要询问如何使用... 的人不太可能对使用... 的设计含义进行大量思考。
  • 也许是这样,但需要询问某些事情并不意味着程序员将永远没有资格使用这些功能。请记住,询问某事是否是个好主意的程序员是有思想的程序员。
【解决方案2】:

你可以将任何你想要的东西传递给可变参数函数,但这不会帮助你编写方便的函数,因为你会丢失参数的类型信息。

根据您想要实现的目标,有更好的选择:

  • 链接运算符,如 << 或 ():

    helper() << a << b << c;
    helper(a)(b)(c);
    
  • 使用(伪)可变参数模板:

    template<class T0>           void func(T0 t0)        { ... }
    template<class T0, class T1> void func(T0 t0, T1 t1) { ... }
    // ...
    
    // or if you can use C++0x features:
    template<class... Args> void func(Args... args) { ... }
    
  • ...更多?

【讨论】:

  • +1 表示运算符重载。可变参数模板看起来只是将问题转移到其他地方而不是解决它。
  • 可变参数模板的关键在于它们是类型安全的,这也是 C 风格可变参数的危险所在。
【解决方案3】:

你可以通过可变参数传递一个类指针,是的。但是接收指针的函数需要知道如何处理它。它必须将其转换为可用的东西。这就是 printf() 让你在格式说明符中指定参数类型的原因。

另一种方法是将列表传递给函数,例如std::vector。

[edit] 你可能想要做一些事情来缩短语法,所以你可以传入你的参数,比如:

foo(blah, StartAList(a)(b)(c)(d));

或流式:

foo(blah) &gt;&gt; a &gt;&gt; b &gt;&gt; c &gt;&gt; d;

或通过重载:

void foo(T a) { ... }
void foo(T a, T b) { ... }
void foo(T a, T b, T c) { ... }

【讨论】:

  • 此外,IIRC 标准(至少在 0x 之前)没有指定对象是按值传递还是通过引用传递。 ---- 它可能也必须是foo(T1, T2, T3)。我们这样做是为了替换sprintf,肯定会生成一个 PITA,但是哦,天哪,它发现了微妙的错误!百万分之一发生的事情,您永远无法通过自动化测试获取的代码路径,等等。
【解决方案4】:

使用 C++0x 可变参数模板,您可以将所有参数打包到一个元组中,并使用我在下面的线程中发布的代码将它们解包到一个函数调用(静态函数或对象函数)中。

How do I expand a tuple into variadic template function's arguments?

【讨论】:

    【解决方案5】:

    使用 C++0x 中新引入的特征变量模板参数可以实现真正的类型安全变量参数函数

    你也可以通过 boost::any 获得

    【讨论】:

    • 好的,但是这种情况是可变模板,并且验证是在编译时完成的。没有什么能比得上完全危险的可变参数函数。 (这是我讨厌 printf 的原因之一,我个人的看法)
    • 这就是为什么您可以使用基于类型安全的可变参数模板的新定义的 printf。 www2.research.att.com/~bs/C++0xFAQ.html#variadic-templates
    • 我还没有阅读这篇文章,但目前我对 std::stringstream 感到非常满意
    【解决方案6】:

    如果总是使用类实例(或指针),最好使用固定参数,它在可变参数列表之前传递,如 printf 中的格式。关于 ... 参数,它们可能具有任何类型(包括类实例或指针),它们的数量和类型取决于调用者和被调用函数之间的某种约定。例如,对于 printf,这种约定由格式字符串定义。您需要定义这样的“通信协议”,它允许使用变量参数列表。当然,这并不安全。

    【讨论】:

      猜你喜欢
      • 2023-03-08
      • 2018-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-29
      相关资源
      最近更新 更多