web-dev-qa-db-ja.com

デフォルトの引数の後にパラメータパックが許可されるのはなぜですか?

明らかな何かが欠けているかもしれませんが、以下はコンパイルして実行し、理由はわかりません。 this を認識していますが、以下の例では、パラメーターパックの位置とデフォルトの引数が逆になっています。デフォルトの引数を最後に表示する必要があるという規則に違反していませんか?パラメータパックにデフォルト値を設定することはできません。

#include <iostream>
#include <string>
#include <Tuple>

template<typename ... Ts>
struct Test
{
    int i;
    std::string str;

    Test(int _i = 0, Ts&& ... _ts)
        :
          i(_i),
          str(std::get<0>(std::forward_as_Tuple(std::forward<Ts>(_ts)...)))
    {}
};

int main()
{
    Test<std::string> t(1, "huh??");
    std::cout << "t.i = " << t.i << ", t.str = " << t.str << "\n";

    return 0;
}

これは生成します

t.i = 1, t.str = huh??
19
cantordust

8.3.6から([dcl.fct.default])/ 4:

テンプレート以外の関数の場合、デフォルトの引数は、同じスコープ内の関数の後の宣言に追加できます。異なるスコープの宣言には、完全に異なるデフォルト引数のセットがあります。つまり、内部スコープの宣言は、外部スコープの宣言からデフォルトの引数を取得しません。その逆も同様です。 特定の関数宣言では、デフォルトの引数を持つパラメーターに続く各パラメーターは、この宣言または前の宣言で指定されたデフォルトの引数を持つか、関数パラメーターパックである必要があります。デフォルトの引数は、後の宣言によって再定義されてはなりません(同じ値であっても)。 [例:

void g(int = 0, ...); // OK, Ellipsis is not a parameter. So it can follow a parameter with a default argument
20
msc

Rspによる優れた回答に加えて、この動作が論理的に意味があることにも注意してください。デフォルト以外のパラメータパック以外の引数は、デフォルトの引数を指定する必要があるという要件が発生しない限り、デフォルトの引数の後に続くことはできません。その場合、デフォルトの引数ではなくなります。

たとえば、次のことが許可されている場合:

_void example(int x=0, int y);
_

デフォルト以外の2番目の引数は、最初のパラメーターをデフォルトにできないため、関数の呼び出しを構造化する必要があることを意味しますexample(1, 2);。これは、空のパラメータパックには当てはまりません。次の関数について考えてみます。

_template <typename... T> void example(int x = 0, T&&... t);
_

この場合でも、example();を呼び出すことでデフォルトのxを使用できます。

10
AzCopey

その理由は簡単です。事実上、パラメーターパックには常にデフォルトがあります。パラメーターパックは空にすることができるため、デフォルトが欠落していることが最後の引数である必要があるという概念と矛盾しません。

8
Gem Taylor