3

std::stringint、などの 3 つのタイプのシーケンスがありますint。関数がそのシーケンスをパラメーターとして無限に取ることを許可するテンプレートは C++ にありますか?

Function("Peter", 27, 89,
         "Max",   25, 72,
         "Frank", 32, 94,
         "David", 31, 98);
4

3 に答える 3

7

問題は、「そのシーケンスと何をしなければならないか」です。

パラメータの任意のシーケンスを取り、それらを 3 つずつ 3 つだけ取る関数に与えることができます。

void Function(string n, int a, int b) 
{ /* base action here */ }

template<class... Others>
void Function(string n1, int a1, int b1, const Others&... t)
{
    Function(n1, a1, b1);
    Function(t...);
}

パラメーターの型が基本関数の型と繰り返し一致する場合にのみコンパイルされます。

于 2013-06-15T13:05:55.187 に答える
5

ここに私の頭に浮かんだいくつかの方法があります:

可変個引数テンプレート: C++11

(Emilio Garavagliaの回答でカバーされているので、繰り返しません)

initializer_lists: C++11

(ChriZzZの答えに似ていますが、代わりにstd::initializer_list直接使用しています)

struct Sequence {
    std::string name;
    int numberA;
    int numberB;
};

#include <initializer_list>
void Function(std::initializer_list<Sequence> aLotOfData)
{
    for(const Sequence& s : aLotOfData)
    {
        // do operations on s.name, s.numberA, s.numberB
    }
}
//usage example
Function({ {"Peter", 27, 89}, {"Max", 25, 72} });

(ここで簡単な解決策のリストを終了します)

N までの引数のオーバーロード関数:

void Function(string n1, int a1, int b1) { /* ??? */ }
void Function(string n1, int a1, int b1, string n2, int a2, int b2) { /* ??? */ }
void Function(string n1, int a1, int b1, string n2, int a2, int b2, string n3, int a3, int b3) { /* ??? */ }
//usage example
Function("Peter", 27, 89, "Max", 25, 72);

実際にはそれほど悪くはありません - 誰もそれを N 個以上の引数で呼び出すことはないと仮定できれば (ちょっとしたトリビア: C 標準では、C コンパイラが 128 個の引数の最小制限をサポートすることを推奨しています)、手動でコーディングしない (プリプロセッサですが、必ずしも C プリプロセッサではありません - 前処理の最小公分母であるため. Boost は、C++11 以外のコードの変数引数に独自のプリプロセッサを使用します. または、C++ プログラムで C++ コードを生成し、出力ファイルをソースに含めることができますコード - これが C++ メタプログラミングです ;-) )。

配列の初期化と関数への受け渡し (またはポインターと を使用sizeof):

struct Sequence
{
    std::string name;
    int numberA;
    int numberB;
};

#include <cstddef>
template<std::size_t N>
void Function(Sequence (&data)[N])
{
    for(std::size_t i = 0; i < N; ++i)
    {
        // do operations on data[i].name, data[i].numberA, data[i].numberB
    }
}
//usage example
Sequence args[] = { {"Peter", 27, 89}, {"Max", 25, 72} };
Function(args);

同様のソリューションを C でも使用できます (C99 では、複合リテラルを使用して引数をインラインで指定することもできます)。

メソッド/関数/演算子の連鎖:

struct Function
{
    const Function& operator()(string name, int na, int nb) const
    {
        // do operations to name, na, nb
        return *this;
    }

    void operator() const
    {
        //base case
        //optional here - return values
    }
};
//usage example
Function()("Peter", 27, 89)("Max", 25, 72)();

チェーンは、C++ iostream と Boost.Assign で使用されます。この実装では、呼び出し元が最後の括弧を含めるのを忘れる可能性があり、関数は最後の処理を実行しません。より良い実装が確実にあるはずです。

C 可変引数:

#include <cstdarg>
void Function(std::size_t count, ...)
{
    va_list ap;
    va_start(ap, count);
    for(std::size_t i = 0; i < count; ++i)
    {
        string name = va_arg(ap, const char*);
        int na = va_arg(ap, int);
        int nb = va_arg(ap, int);
        // do operations on name, na, nb
    }
    va_end(ap);
}
//usage example (the first argument refers to count of arguments - it has to match)
Function(2, "Peter", 27, 89, "Max", 25, 72);

非常に悪い解決策です。非 POD は varargs 関数に渡すことができない (または へのポインターを渡すことができる) ため、引数として破棄std::stringし、 に置き換える必要がありました。ここで間違いがあると、未定義の動作が発生することに注意してください。コンパイラは引数の型をチェックせず、正しい型の引数が渡されたことを盲目的に信頼します。const char*std::string

于 2013-06-16T02:17:26.447 に答える
1

構造体とある種のコンテナを使用するだけです。

void Function(std::vector<Sequence> aLotOfData);


struct Sequence {
    std::string name;
    int numberA;
    int numberB;
};
于 2013-06-15T13:03:50.290 に答える