関数パラメーターのデフォルト値


130

1。

int Add (int a, int b = 3);
int Add (int a, int b)
{

}

2。

int Add (int a, int b);
int Add (int a, int b = 3)
{

}

どちらも機能します。どちらが標準的な方法で、なぜですか?

回答:


203

宣言をヘッダーファイルに入れ、定義を別の.cppファイルに入れ#include、ヘッダーを別の.cppファイルに入れると、違いを確認できます。

具体的には、次のように仮定します。

lib.h

int Add(int a, int b);

lib.cpp

int Add(int a, int b = 3) {
   ...
}

test.cpp

#include "lib.h"

int main() {
    Add(4);
}

のコンパイルでtest.cppは、デフォルトのパラメータ宣言が表示されず、エラーが発生して失敗します。

このため、デフォルトのパラメーター定義は通常、関数宣言で指定されます。

lib.h

int Add(int a, int b = 3);

次にb、を含むコンパイル単位ごとに一度、複数回定義されlib.hますか?
httpinterpret 2010年

@httpinterpret:ある意味でbは、のデフォルト値は、ヘッダーを含む .cppファイルに対して1回定義されます。ただし、Add関数の宣言は1つしかないため、問題ありません。
グレッグヒューギル

1
@httpinterpretコンパイラは、呼び出し元のコードが生成されるときに、デフォルトパラメータによって指定されていないパラメータを追加します。そのため、デフォルト値は関数実装ではなく関数プロトタイプにある必要があります。プロトタイプは変数を定義しないため、パラメーターは変数定義の意味で定義されていません。
ハーパー

1
この答えは編集できたかもしれません。なぜなら、迅速な構文解析(コードを見て、「この理由で」までは行かない)によって、あなたの意図とは正反対のことが理解できたからです。
Gabriel Devillers 2018年

44

C ++では、パラメーターリスト内の場所に関してデフォルト引数に課される要件は次のとおりです。

  1. 特定のパラメーターのデフォルト引数は、1回のみ指定する必要があります。同じデフォルト値でも、2回以上指定することはできません。

  2. デフォルトの引数を持つパラメータは、パラメータリストの最後に隣接するグループを形成する必要があります。

これを念頭に置いて、C ++では、上記の要件が継続的に満たされている限り、関数の宣言から次の宣言にデフォルト引数を持つパラメーターのセットを「拡張」することができます。

たとえば、デフォルトの引数なしで関数を宣言できます

void foo(int a, int b);

このような宣言の後にその関数を呼び出すには、両方の引数を明示的に指定する必要があります。

同じ翻訳単位の後で(さらに下に)、もう一度再宣言できますが、今回は1つのデフォルト引数を使用します

void foo(int a, int b = 5);

この時点から、明示的な引数を1つだけ指定して呼び出すことができます。

さらに下の方で、再宣言して、デフォルト引数をもう1つ追加できます。

void foo(int a = 1, int b);

この時点から、明示的な引数なしで呼び出すことができます。

完全な例は次のようになります

void foo(int a, int b);

int main()
{
  foo(2, 3);

  void foo(int a, int b = 5); // redeclare
  foo(8); // OK, calls `foo(8, 5)`

  void foo(int a = 1, int b); // redeclare again
  foo(); // OK, calls `foo(1, 5)`
}

void foo(int a, int b)
{
  // ...
}

あなたの質問のコードについては、どちらのバリアントも完全に有効ですが、意味が異なります。最初のバリアントは、2番目のパラメーターのデフォルト引数をすぐに宣言します。2番目のバリアントは、最初にデフォルトの引数なしで関数を宣言し、次に2番目のパラメーターに1つ追加します。

両方の宣言の正味の効果(つまり、2番目の宣言に続くコードで見られる方法)はまったく同じです。関数には2番目のパラメーターのデフォルト引数があります。ただし、最初の宣言と2番目の宣言の間にコードを詰め込んだ場合、これらの2つのバリアントの動作は異なります。2番目のバリアントでは、関数は宣言の間にデフォルトの引数を持たないため、両方の引数を明示的に指定する必要があります。


あなたのコードで定義されたvoid foo(int a = 1、int b)が機能するとは思いません。1つのオプションパラメータの後にすべてのオプションパラメータが必要です。これは構文エラーです(少なくとも私のシステムのg ++​​ 4.5.3では)。
ニレシュ

@Nilesh:上で明示的に言ったように(これはこの例の要点です)、void foo(int a = 1, int b)動作させるには、の に宣言する必要がありvoid foo(int a, int b = 5)ます。はい、動作します。いいえ、それは構文エラーではありません。g ++ 4.5.3は完全にコンパイルします。
Antの

さて、関数は前の宣言からbの値を取ります。物事を今取得しています。おかげで:-)
Nilesh

1
@Nilesh:はい、デフォルトの引数宣言は、翻訳単位内の以前のすべての宣言にわたって累積されます。
AnT

1
のように、変数名を付けずに関数のプロトタイプを書くのが好きint foo(int)です。int foo(int=5)パラメータ名を省いて、もう一度書くことができることがわかりました。まだ誰もそれについて言及していないようです。
ビクターアイクハウト2017

5

最初の方法は2番目の方法よりも優先されます。

これは、ヘッダーファイルにパラメーターがオプションであり、そのデフォルト値が何であるかが示されるためです。さらに、これにより、対応する.cppファイルの実装に関係なく、デフォルト値が同じになります。

2番目の方法では、2番目のパラメーターのデフォルト値の保証はありません。対応する.cppファイルの実装方法に応じて、デフォルト値が変わる可能性があります。


4

デフォルト引数は、最初に出現する関数名を使用して指定する必要があります。通常、関数プロトタイプ内です。関数のプロトタイプがプロトタイプとしても機能するために関数のプロトタイプが省略されている場合、デフォルトの引数を関数ヘッダーで指定する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.