36

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);
}
4

8 に答える 8

50

これらはVariadic 関数と呼ばれます。ウィキペディアには、 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;
}
于 2009-10-16T18:47:06.623 に答える
6

他の答えは別として、整数の配列を渡そうとしているだけなら、そうではありません:

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);

ただし、パラメーター、フォームで呼び出すことはできません。回答にリストされている可変長関数のいずれかを使用する必要があります。C++0x は可変個引数テンプレートを許可するため、タイプ セーフになりますが、現時点では基本的にメモリとキャストです。

ある種の可変パラメータ -> ベクトルをエミュレートできます。

// 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));
于 2009-10-16T18:55:11.100 に答える
3

C、Objective-C、C++、および D の Variadic 関数を参照してください。

ウィキペディアの記事の例が示すように、stdarg.hva_listをインクルードしてから、、、およびを使用する必要があります。C および C++ では可変引数の組み込みサポートが制限されているため、Java や C# よりも少し面倒です。va_startva_argva_end

于 2009-10-16T18:47:19.530 に答える
1

移植性を気にしない場合は、gcc のステートメント式を使用して、この C99 コードを C++ に移植できます。

#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 のラムダ式でも同様のことができますが、私が使用している gcc バージョン (4.4.0) はそれらをサポートしていません。

于 2009-10-16T22:19:56.197 に答える