代码之家  ›  专栏  ›  技术社区  ›  AndreyAkinshin

C++中函数中变量的变量数

  •  31
  • AndreyAkinshin  · 技术社区  · 15 年前

    如何在C++中的函数中有可变数量的参数。

    C#中的模拟:

    public void Foo(params int[] a) {
        for (int i = 0; i < a.Length; i++)
            Console.WriteLine(a[i]);
    }
    
    public void UseFoo() {
        Foo();
        Foo(1);
        Foo(1, 2);
    }
    

    Java中的模拟:

    public void Foo(int... a) {
        for (int i = 0; i < a.length; i++)
            System.out.println(a[i]);
    }
    
    public void UseFoo() {
        Foo();
        Foo(1);
        Foo(2);
    }
    
    8 回复  |  直到 15 年前
        1
  •  50
  •   Stephan202 Alex Martelli    15 年前

    这些被称为 Variadic functions . 维基百科列表 example code for C++ .

    C语言编程中的函数 stdarg.h 应使用文件。老年人 已弃用varargs.h标头 有利于stdarg.h。 在C++中 头文件 cstdarg

    要创建可变函数,请使用 省略号( ... )必须放置在 函数体,一个 类型 va_list va_start(va_list, last fixed param) , va_arg(va_list, cast type) , va_end(va_list) 可以使用。对于

    #include <stdarg.h>
    
    double average(int count, ...)
    {
        va_list ap;
        int j;
        double tot = 0;
        va_start(ap, count); //Requires the last fixed parameter (to get the address)
        for(j=0; j<count; j++)
            tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
        va_end(ap);
        return tot/count;
    }
    
        2
  •  20
  •   Community c0D3l0g1c    7 年前

    真正的C++解决方案是可变模板。您将需要一个相当新的编译器,并在需要时启用C++11支持。

    有两种方法可以处理“对所有函数参数执行相同的操作”问题:递归方式和丑陋(但非常符合标准)的解决方案。

    recursive solution 看起来有点像这样:

    template<typename... ArgTypes>
    void print(ArgTypes... args);
    template<typename T, typename... ArgTypes>
    void print(T t, ArgTypes... args)
    {
      std::cout << t;
      print(args...);
    }
    template<> void print() {} // end recursion
    

    它为每个参数集合生成一个符号,然后为递归的每个步骤生成一个符号。这至少可以说是次优,所以 the awesome C++ people here at SO 想到 a great trick abusing the side effect of a list initialization

    struct expand_type {
      template<typename... T>
      expand_type(T&&...) {}
    };
    template<typename... ArgTypes>
    void print(ArgTypes... args)
    { 
      expand_type{ 0, (std::cout << args, 0)... };
    }
    

    不会为一百万个略有不同的模板实例化生成代码,另外,您可以保留函数参数的顺序。有关此解决方案的详细信息,请参见另一个答案。

        3
  •  13
  •   Seb    8 年前

    在C++11及更高版本中,还可以使用初始值设定项列表。

    int sum(const initializer_list<int> &il)
    {
        int nSum = 0;
        for (auto x: il) 
            nSum += x;
        return nsum;
    }
    
    cout << sum( { 3, 4, 6, 9 } );
    
        4
  •  6
  •   GManNickG    15 年前

    void func(const std::vector<int>& p)
    {
        // ...
    }
    
    std::vector<int> params;
    params.push_back(1);
    params.push_back(2);
    params.push_back(3);
    
    func(params);
    

    您可以模拟某种可变参数->向量事物:

    // would also want to allow specifying the allocator, for completeness
    template <typename T> 
    std::vector<T> gen_vec(void)
    {
        std::vector<T> result(0);
        return result;
    }
    
    template <typename T> 
    std::vector<T> gen_vec(T a1)
    {
        std::vector<T> result(1);
    
        result.push_back(a1);
    
        return result;
    }
    
    template <typename T> 
    std::vector<T> gen_vec(T a1, T a2)
    {
        std::vector<T> result(1);
    
        result.push_back(a1);
        result.push_back(a2);
    
        return result;
    }
    
    template <typename T> 
    std::vector<T> gen_vec(T a1, T a2, T a3)
    {
        std::vector<T> result(1);
    
        result.push_back(a1);
        result.push_back(a2);
        result.push_back(a3);
    
        return result;
    }
    
    // and so on, boost stops at nine by default for their variadic templates
    

    用法:

    func(gen_vec(1,2,3));
    
        5
  •  3
  •   Jesper    15 年前

    Variadic functions in C, Objective-C, C++, and D

    你需要包括 stdarg.h 然后使用 va_list , va_start , va_arg va_end ,正如维基百科文章中的例子所示。这比java或C++中的麻烦多了,因为C和C++对VARARGS只有有限的内置支持。

        6
  •  1
  •   Community c0D3l0g1c    7 年前

    如果你不关心可移植性,你可以移植 this C99 code gcc's statement expressions :

    #include <cstdio>
    
    int _sum(size_t count, int values[])
    {
        int s = 0;
        while(count--) s += values[count];
        return s;
    }
    
    #define sum(...) ({ \
        int _sum_args[] = { __VA_ARGS__ }; \
        _sum(sizeof _sum_args / sizeof *_sum_args, _sum_args); \
    })
    
    int main(void)
    {
        std::printf("%i", sum(1, 2, 3));
    }
    

    您可以对C++0x'lambda表达式执行类似的操作,但我使用的gcc版本(4.4.0)不支持它们。

        7
  •  1
  •   user2133061 user2133061    10 年前

    GManNickG和Christoph的答案是好的,但变量函数允许您按 ... 参数,而不仅仅是整数。如果你 将来 ,以推送 不同的 在不使用变量函数的情况下键入函数,因为它对您来说太难或太复杂,或者您不喜欢使用它的方式,或者您不想包含使用它所需的标题,那么您始终可以使用 void**

    例如,Stephan202发布了:

    double average(int count, ...)
    {
        va_list ap;
        int j;
        double tot = 0;
        va_start(ap, count); //Requires the last fixed parameter (to get the address)
        for(j=0; j<count; j++)
            tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
        va_end(ap);
        return tot/count;
    }
    

    这也可以写成:

    double average(int count, void** params)
    {
        int j;
        double tot = 0;
        for (j=0; j<count; j++)
           tot+=*(double*)params[j];
        return tot/count;
    }
    

    现在这样使用它:

    int _tmain(int argc, _TCHAR* argv[])
    {
        void** params = new void*[3];
        double p1 = 1, p2 = 2, p3 = 3;
        params[0] = &p1;
        params[1] = &p2;
        params[2] = &p3;
        printf("Average is: %g\n", average(3, params));
        system("pause");
        return 0;
    }
    

    完整代码:

    #include "stdafx"
    #include <process.h>
    
    double average(int count, void** params)
    {
        int j;
        double tot = 0;
        for (j=0; j<count; j++)
            tot+=*(double*)params[j];
        return tot/count;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        void** params = new void*[3];
        double p1 = 1, p2 = 2, p3 = 3;
        params[0] = &p1;
        params[1] = &p2;
        params[2] = &p3;
        printf("Average is: %g\n", average(3, params));
        system("pause");
        return 0;
     }
    

    输出:

    平均值为:2

    按任意键继续。

        8
  •  0
  •   HMD Purnendu Sarkar    6 年前

    String s[] = {"hello ", " unli", " param", " test"};
    String ret = BuildList(s, 4);
    
    String BuildList(String s[], int count)
    {
        for(int i = 0; i < count; i++)
        {
            //.... loop here up to last s[i] item ... 
        }
    }