【问题标题】:c++ functions with variable and not known number of arguments [duplicate]具有变量且参数​​数量未知的c ++函数[重复]
【发布时间】:2012-07-16 23:07:11
【问题描述】:

可能重复:
Variable number of arguments in C++?

我可以不设置具有可变参数数量的函数的参数数量吗?举个例子:下面的接口可以实现吗?

int sum(...) { ... }

sum(1, 2, 3, 4); // return 10

【问题讨论】:

  • 不应该很难设置一个可变参数模板来做到这一点,假设你的编译器支持它们。我会发布一个答案,但我没有这样的编译器来测试我的代码。

标签: c++ function


【解决方案1】:

传统的variadic functions 很混乱,而且不是类型安全的,但在C++11 中,您可以使用variadic templates 和(编译时)递归干净地做到这一点:

// Base case for recursion
template <typename T>
inline T sum(T n) {
  return n;
}

// Recursive case
template <typename T, typename... Args>
inline T sum(T n, Args... args) {
  return n + sum(args...);
}

由于它是一个模板,因此它适用于定义了 operator+ 的任何类型:

std::cout << sum(1, 2, 3) << std::endl;  // Prints 6
std::cout << sum(3.14, 2.72) << std::endl;  // Prints 5.86

但是,由于递归模板函数的返回类型仅取自第一个参数,如果在一次调用中混合不同的参数类型,您会得到令人惊讶的结果:sum(2.5, 2) 按预期返回 4.5,但 sum(2, 2.5) 返回2 因为返回类型是int,而不是double。如果您想花哨,可以使用新的alternative function syntax 指定返回类型是n + sum(args...) 的自然类型:

// Recursive case
template <typename T, typename... Args>
inline auto sum(T n, Args... args) -> decltype(n + sum(args...)) {
  return n + sum(args...);
}

现在 sum(2.5, 2)sum(2, 2.5) 都返回 4.5。

如果您的实际逻辑比求和更复杂,并且您不希望它内联,您可以使用内联模板函数将所有值放入某种容器中(例如 std::vectorstd::array ) 并将其传递给非内联函数以在最后完成真正的工作。

【讨论】:

  • 如果您使用可变参数模板,我猜您使用的是 GCC。尾随返回语法 works fine on ideone 以及来自 nuwen.net/mingw.html 的 GCC 4.7.1。如果您有兴趣,这是一个很好的发行版。
  • @chris,我使用的是 GCC 4.7.1,并且我知道尾随返回语法通常有效。但是使用decltype(n + sum(args...)) 的返回类型没有编译——它抱怨找不到匹配的模板。我尝试了一些东西,但没有花很多时间。
  • 好的,我在递归 sum 的末尾尝试了那个确切的代码,它工作得很好:inline auto sum (T n, Args... args) -&gt; decltype (n + sum(args...))
  • 奇怪,现在它也适用于我。我上次一定是在什么地方打错了。感谢您的健全性检查。
【解决方案2】:

您可能希望通过编写函数来获取类似 vector&lt;int&gt; 的内容,您将使用花括号初始化列表动态构建它:

int sum(std::vector<int> const &n) { 
    return std::accumulate(begin(n), end(n), 0);
}

如果数字可能是(例如)浮点数,您可能希望将其编写为模板:

template <class T>
T sum(std::vector<T> const &n) { 
   return std::accumulate(begin(n), end(n), T());
}

无论哪种方式,您调用它的方式都会略有不同:

int x = sum({1,2,3,4});

警告:此功能是最近才添加到 C++ 中的,因此一些编译器(例如 VC++)还不支持它——尽管其他编译器(例如 g++ 4.7+)支持。

【讨论】:

  • 也可以template&lt;std::size_t N&gt; int sum(const std::array&lt;int, N&gt;&amp; n) { ... }
  • @DeadMG:好点子——这可能是不支持 C++11 的编译器的最佳选择。
  • @DeadMG:如何调用函数?
  • @Marshall, std::array 不会重载构造函数来获取初始化列表。相反,您可以使用sum&lt;3&gt;({{2, 3, 5}});
【解决方案3】:

不,你不能。

只是不要使用可变参数。他们吸收了所有可以想象的时尚,完全不值得任何人花时间。

【讨论】:

    【解决方案4】:

    C++ 可变参数函数必须知道它传递了多少(以及什么类型)的参数。例如,printf 的格式字符串告诉它期望什么额外的参数。

    您的 sum 无法知道它是 4 个整数还是 10 个整数。您可以将第一个参数设为长度:

    int sum(int howmany, ...) { ... }
    

    所以函数知道后面有多少个整数。但实际上你应该只传递一个数组(或向量,如果你感觉 C++'y)

    【讨论】:

    • 如果你真的很喜欢冒险,你可以使用将函数调用包装在一个 Boost 宏中,该宏会预先设置参数数量...
    【解决方案5】:

    有多种方法可以解决您的问题。我会介绍几个:

    方法一: - 创建一系列重载求和函数以满足您的需求。

    缺点 -代码膨胀

    这可以通过使用 headers 制作多个函数来实现:

    int sum(int a);
    int sum(int a, int b);
    int sum(int a, int b, int c);
    

    等等……

    方法二: - 创建一个带有链表的自定义类,并传入一个指向链表头部的指针。假设您不知道要传入的数据量,这可能是您在这种情况下的最佳做法。

    函数头:

    int sum(LinkedList *headPointer);
    

    方法三: - 传入一个变量数组

    函数头:

    int sum(int input[]);
    

    方法四: - 创建一个带有自动设置变量的函数

    函数头:

    int sum(int a=0, int b=0, int c=0, int d=0,... int n=0);
    

    【讨论】:

    • 另一个:int sum(int a=0, int b=0, int c=0, int d=0, int e=0) {...}
    • 为什么是自定义列表类而不是 STL 中的容器?
    • 好调用 luskan,这是另一种方法,它会自动将你没有传入的变量设置为 0。可以根据你的功能工作。
    • @betabandido 无论哪种方式都可以,我使用自定义列表类来提供它提供的学习体验。作为一个很好的复习
    • @kabirpong 确实,如果您想刷新列表的制作方式可能是个好主意,但在向其他人提供建议时可能不是最好的主意:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 2019-12-15
    • 1970-01-01
    • 2011-07-14
    • 2014-11-25
    相关资源
    最近更新 更多