4

私はクラスメンバーを持っています:

LineND::LineND(double a ...)
{
    coefficients.push_back(a);
    va_list arguments;
    va_start(arguments, a);
    double argValue;
    do
    {
        argValue = va_arg(arguments, double);
        coefficients.push_back(argValue);
    }while(argValue != NULL);   // THIS IS A PROBLEM POINT!
    va_end(arguments);
}

いくつの引数が使用されるかわかりません。各引数を取り、それを というベクトルに入れる必要がありますcoefficients。どうすればいいですか?この場合、その記述while(argValue != NULL)が正しくないことは理解しています。たとえば、次の署名は使用できません。

LineND::LineND(int numArgs, double a ...)

次のように条件を変更します。

while(argValue != numArgs);

ポイントは、メソッドのシグネチャを変更できないことです。この問題を別の方法で解決する必要があります。

4

5 に答える 5

15

可変引数リストにはいくつかの欠点があります。

  • 呼び出し元は、必要なものすべてを渡すことができます。
  • POD 以外のオブジェクトが渡されると、未定義の動作が呼び出されます
  • 引数の数に頼ることはできません (呼び出し元がエラーを起こす可能性があります)。
  • ライブラリコードをより簡単に使用できるようにすることを意図したクライアントに多くの責任を負わせます (実際の例: format-string-bugs/-errors)

可変個引数テンプレートとの比較:

  • コンパイル時のリスト サイズがわかっている
  • 型はコンパイル時に認識されます
  • クライアントではなく、物事に対する責任はあなたにあります。

例:

void pass_me_floats_impl (std::initializer_list<float> floats) {
    ...
}

これは、クラス宣言のプライベート セクションまたは詳細名前空間に配置できます。注:pass_me_floats_impl()ヘッダーに実装する必要はありません。

次に、クライアントにとって良いことは次のとおりです。

template <typename ...ArgsT>
void pass_me_floats (ArgsT ...floats) {
    pass_me_floats_impl ({floats...});
}

彼は今できること:

pass_me_floats ();
pass_me_floats (3.5f);
pass_me_floats (1f, 2f, 4f);

しかし、彼はできません:

pass_me_floats (4UL, std::string());

pass_me_floats-function 内でコンパイル エラーが発生するためです。

少なくとも2 つの引数が必要な場合は、次のようにします。

template <typename ...ArgsT>
void pass_me_floats (float one, float two, ArgsT... rest) {}

もちろん、完全なインライン関数が必要な場合は、次のこともできます

template <typename ...ArgsT>
void pass_me_floats (ArgsT... rest) {
    std::array<float, sizeof...(ArgsT)> const floaties {rest...};

    for (const auto f : floaties) {}
}
于 2012-06-14T10:00:36.210 に答える
1

メソッドを take に書き換える必要がありますstd::initializer_list<double>

それができず、パラメーターを追加できない場合、count修正は引数リストを終了する番兵値を取ることです。0.0NaN

たとえば、可変数のポインターを受け取る関数はNULL、センチネル値として使用します。構造体のリストを取る関数は、番兵として 0 で初期化された構造体を取ります。これは、C API ではかなり一般的です。http://c-faq.com/varargs/nargs.htmlを参照してください。例は次のとおりです。execl("/bin/sh", "sh", "-c", "date", (char *)NULL);

于 2012-06-14T09:51:37.080 に答える
0

引数リストの最初の double を引数の実際の数にします。

于 2012-06-14T09:54:44.207 に答える