如何使函数接受不使用f(...)的任意数量的参数?

xml*_*lmx 6 c++ templates function variadic-templates c++11

一段代码胜过千言万语:

int main()
{
    // All of the following calls return true:
    AreEqual(1, 1);
    AreEqual(1, 1, 1);
    AreEqual(1, 1, 1, 1);
    AreEqual(1, 1, 1, 1, 1);

    // All of the following calls return false:
    AreEqual(1, 2);
    AreEqual(1, 2, 1);
    AreEqual(1, 7, 3, 1);
    AreEqual(1, 4, 1, 1, 1);    
}
Run Code Online (Sandbox Code Playgroud)

如何实现接受任意数量参数的函数AreEqual()?

琐碎但乏味的灵魂是通过重载:

bool AreEqual(int v1, int v2);
bool AreEqual(int v1, int v2, int v3);
bool AreEqual(int v1, int v2, int v3, int v4);
......
Run Code Online (Sandbox Code Playgroud)

另一个微不足道但不可行的解决方案是:

bool AreEqual(...);
Run Code Online (Sandbox Code Playgroud)

此解决方案不可行,因为调用者必须添加另一个参数(参数计数或结束标记)以指定参数的数量.

另一种方法是通过可变参数模板参数

template<class... Args>
bool AreEqual(Args... args)
{
    // What should be placed here ???
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*obᵩ 11

以下是如何使用模板实现它:

#include <iostream>
#include <iomanip>

template<class T0>
bool AreEqual(T0 t0) { return true; }

template<class T0, class T1, class... Args>
bool AreEqual(T0 t0, T1 t1, Args ... args) {
  return t0 == t1 && AreEqual(t1, args...);
}


int main () {
  std::cout << std::boolalpha;

    // All of the following calls return true:
  std::cout<< AreEqual(1, 1) << "\n";
  std::cout<< AreEqual(1, 1, 1) << "\n";
  std::cout<< AreEqual(1, 1, 1, 1) << "\n";
  std::cout<< AreEqual(1, 1, 1, 1, 1) << "\n\n";

    // All of the following calls return false:
  std::cout<< AreEqual(1, 2) << "\n";
  std::cout<< AreEqual(1, 2, 1) << "\n";
  std::cout<< AreEqual(1, 7, 3, 1) << "\n";
  std::cout<< AreEqual(1, 4, 1, 1, 1)  << "\n";
}
Run Code Online (Sandbox Code Playgroud)

您应该考虑这些变化是否适合您的使用:

  • 使用引用而不是传值
  • 使非变量模板采用两个参数而不是一个.


或者,这是一个非递归版本.可悲的是,它并不是短暂的.要查看非递归短路版本,请参阅另一个答案.

template<typename T, typename... Args>
bool AreEqual(T first, Args... args)
{
  return std::min({first==args...});
}
Run Code Online (Sandbox Code Playgroud)


最后,这个版本缺乏微妙的吸引力:

template<typename T, typename... Args>
bool AreEqual(T first, Args... args)
{
  for(auto i : {args...})
    if(first != i)
      return false;
  return true;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您的编译器有任何好处,它将完全独立于是否使用`inline`关键字生成内联代码(或不生成). (4认同)