我们如何更改此函数以支持多个参数?

时间:2013-11-27 06:16:55

标签: c++ c++11

#include <iostream>    
using namespace std;

class SampleClass
{
  public:      
    int test(int ... arguments)
    {
        cout << arguments[0] << endl; // Access first element in array
        return sizeof(arguments);
    }
};

int main()
{   
   SampleClass lol;       
   cout << lol.test(3, 1, 4, 2, 5, 0) << endl;       
   return 0;
}

由于我对C ++语义的理解有限,test函数失败了。但是我如何修复它以便它可以访问参数lits中的FIRST元素然后返回arguments的大小?

<小时/> 正如@Nik指出的那样,我显然可以通过一个数组,但这并没有真正的乐趣!我试图这样做只是为了学习 - 看看这是否可能在C ++中。

5 个答案:

答案 0 :(得分:3)

尝试这样的事情

double test( int num, ... )
{
  va_list arguments;                     // A place to store the list of arguments
  double sum = 0;

  va_start ( arguments, num );           // Initializing arguments to store all values after num
  for ( int x = 0; x < num; x++ )        // Loop until all numbers are added
    sum += va_arg ( arguments, double ); // Adds the next value in argument list to sum.
  va_end ( arguments );                  // Cleans up the list

  return sum / num;                      // Returns the average
}

所以你的参数列表中的点是错误的。 我希望这有助于和好运。

答案 1 :(得分:3)

嗯。您正在尝试混合使用C ++的两个功能,variadic-templatesvariable-length argument list。 你的代码根本不会编译,因为你这里没有模板,variable-length argument list声明应该是

int test(int arguments...)

您可以使用cstdarg标题中的函数访问此列表中的值。

使用variadic-templates,您可以执行以下操作

class Derived
{
public:
    template<int... arguments>
    int test()
    {
       int array[] = {arguments...};
       return sizeof(array) / sizeof(*array);
    }
};

一样使用它
cout << lol.test<3, 1, 4, 2, 5, 0>() << endl;

答案 2 :(得分:3)

既然我们都在猜你想要什么,我会投入:

template <typename ... Ts>
size_t test(Ts ... arguments) {
    auto unused = { 0, ((cout << '[' << arguments << "]\n"), 0)...};
    (void)unused;
    return sizeof...(arguments);
}

适用于不同类型的参数(Live at Coliru)。但是,这个解决方案有点过于“聪明”,无法读取。

这里的技巧是构建一个braced-initializer-list - {...}东西 - 通过按顺序处理可变参数来初始化其元素。然后你说服编译器说所谓的初始化列表没有用于任何东西,所以代码将被优化以产生所需的副作用。

C ++中的逗号运算符求值为最右边的子表达式的值。评估其他子表达式并丢弃它们的值。因此((cout << '[' << arguments << "]\n"), 0)具有将某些内容转储到cout的效果 - 包括其中一个可变参数 - 并且计算结果为0.使用...扩展包后该代码行有效:

auto unused = { 0, ((cout << '[' << arg0 << "]\n"), 0),
                   ((cout << '[' << arg1 << "]\n"), 0),
                   ((cout << '[' << arg2 << "]\n"), 0) };

评估cout垃圾的副作用并将其丢弃,整个事情被推断为std::initializer_list<int>,就像我们写的那样

auto unused = { 0, 0, 0, 0 };

(如果有人用 no 参数调用该函数,那么开头就会出现额外的零以避免语法错误。)

(void)unused;行将unused投射到void。它将编译为绝对没有,但通常也会告诉编译器不要警告我们unused是一个未使用的变量。

答案 3 :(得分:2)

我不太确定我完全理解你的问题。如果你想访问&#34;第一个&#34;函数的参数而不是模板,我认为这样的东西会为你做,但我可能完全误解了你的目的:

#include <iostream>

template<typename... Args>
int foo(int arg0, Args... args);

template<>
int foo(int arg0)
{
    // here just to catch expansion
    std::cout << '[' << arg0 << ']' << std::endl;
    return 1;
}

template<typename... Args>
int foo(int arg0, Args... args)
{
    foo(arg0);
    foo(args...);
    return 1 + sizeof...(args);
}

int main()
{
    std::cout << foo(1,2,3,4,5) << std::endl;
    std::cout << foo(100,200,300) << std::endl;

    int a=10, b=20;
    std::cout << foo(a,b) << std::endl;

    return 0;
}

<强>输出

[1]
[2]
[3]
[4]
[5]
5
[100]
[200]
[300]
3
[10]
[20]
2

答案 4 :(得分:1)

您有几种选择。

1)使用椭圆(只有这样才能拥有无限的arg列表):

int foo(int a1, ...);

您的代码需要像printf一样解析椭圆。你将被限制在内置C类型。

2)使用多个模板:

template<typename T1> int foo(T1 a1);
template<typename T1, typename T2> int foo(T1 a1, T2 a2);

// more templates for more arguments

This method us used, usually up to 10 parameters (10 template functions)

3)使用具有默认值或非法值的函数,以便您知道哪个是最后一个有效参数:

 int foo(int a1, int a2 = -1, int a3 = -1, int aN = -1);