デフォルト引数
関数呼び出しで1つ以上の末尾引数を指定せずに呼び出すことを可能にします。
関数宣言のparameter-list内のパラメータに以下の構文を使用することで示されます。
attr (optional) decl-specifier-seq declarator = initializer |
(1) | ||||||||
attr (optional) decl-specifier-seq abstract-declarator (optional) = initializer |
(2) | ||||||||
デフォルト引数は、関数呼び出しで省略された末尾引数の代わりに使用されます。
void point(int x = 3, int y = 4); point(1, 2); // calls point(1, 2) point(1); // calls point(1, 4) point(); // calls point(3, 4)
関数宣言では、デフォルト引数を持つパラメータの後には、続くすべてのパラメータが
- 同じスコープ内のこの宣言または以前の宣言でデフォルト引数を指定する必要があります。
int x(int = 1, int); // Error: only the trailing parameters can have default arguments // (assuming there's no previous declaration of “x”) void f(int n, int k = 1); void f(int n = 0, int k); // OK: the default argument of “k” is provided by // the previous declaration in the same scope void g(int, int = 7); void h() { void g(int = 1, int); // Error: not the same scope }
template<class... T> struct C { void f(int n = 0, T...); }; C<int> c; // OK; instantiates declaration void C::f(int n = 0, int)
template<class... T> void h(int i = 0, T... args); // OK |
(C++11以降) |
省略記号はパラメータではないため、デフォルト引数を持つパラメータの後に続けることができます。
int g(int n = 0, ...); // OK
デフォルト引数は、関数宣言およびラムダ式のパラメータリストでのみ許可され、(C++11以降)関数へのポインタ、関数への参照、またはtypedef宣言では許可されません。テンプレートパラメータリストは、デフォルトテンプレート引数に対して同様の構文を使用します。
非テンプレート関数では、同じスコープで関数が再宣言された場合、既に宣言されている関数にデフォルト引数を追加できます。関数呼び出しの時点では、デフォルト引数は、関数に対してすべての可視な宣言で提供されたデフォルト引数の結合です。再宣言によって、デフォルト引数が既に可視であるパラメータに対してデフォルト引数を導入することはできません(値が同じであっても)。内側のスコープでの再宣言は、外側のスコープからデフォルト引数を取得しません。
void f(int, int); // #1 void f(int, int = 7); // #2 OK: adds a default argument void h() { f(3); // #1 and #2 are in scope; makes a call to f(3,7) void f(int = 1, int); // Error: the default argument of the second // parameter is not acquired from outer scopes } void m() { // new scope begins void f(int, int); // inner scope declaration; has no default argument. f(4); // Error: not enough arguments to call f(int, int) void f(int, int = 6); f(4); // OK: calls f(4, 6); void f(int, int = 6); // Error: the second parameter already has a // default argument (even if the values are the same) } void f(int = 1, int); // #3 OK, adds a default argument to #2 void n() { // new scope begins f(); // #1, #2, and #3 are in scope: calls f(1, 7); }
インライン関数が異なる翻訳単位で宣言されている場合、各翻訳単位の終わりに、蓄積されたデフォルト引数のセットは同じでなければなりません。
|
非インライン関数が異なる翻訳単位で同じ名前空間スコープで宣言されている場合、対応するデフォルト引数は、存在すれば同じでなければなりません(ただし、一部のデフォルト引数は一部のTUで存在しない場合があります)。 |
(C++20以降) |
フレンド宣言がデフォルト引数を指定する場合、それはフレンド関数定義でなければならず、この関数の他の宣言は翻訳単位で許可されません。
using宣言は既知のデフォルト引数のセットを引き継ぎ、後で関数の名前空間にデフォルト引数が追加された場合、それらのデフォルト引数もusing宣言が可視な場所で可視になります。
namespace N { void f(int, int = 1); } using N::f; void g() { f(7); // calls f(7, 1); f(); // error } namespace N { void f(int = 2, int); } void h() { f(); // calls f(2, 1); }
デフォルト引数で使用される名前は、宣言の時点でルックアップされ、アクセシビリティがチェックされ、バインドされますが、関数呼び出しの時点で実行されます。
int a = 1; int f(int); int g(int x = f(a)); // lookup for f finds ::f, lookup for a finds ::a // the value of ::a, which is 1 at this point, is not used void h() { a = 2; // changes the value of ::a { int a = 3; g(); // calls f(2), then calls g() with the result } }
非テンプレート化クラスのメンバ関数の場合、デフォルト引数はクラス外の定義で許可され、クラス本体内の宣言によって提供されるデフォルト引数と結合されます。これらのクラス外のデフォルト引数によってメンバ関数がデフォルトコンストラクタまたはコピー/ムーブ(C++11以降)コンストラクタ/代入演算子に変わる場合(呼び出しがあいまいになる場合)、プログラムは不正な形式になります。テンプレート化クラスのメンバ関数については、すべてのデフォルト引数はメンバ関数の最初の宣言で提供されなければなりません。
class C { void f(int i = 3); void g(int i, int j = 99); C(int arg); // non-default constructor }; void C::f(int i = 3) {} // error: default argument already // specified in class scope void C::g(int i = 88, int j) {} // OK: in this translation unit, // C::g can be called with no argument C::C(int arg = 1) {} // Error: turns this into a default constructor
仮想関数のオーバーライダは基底クラス宣言からデフォルト引数を取得せず、仮想関数呼び出しが行われる際、デフォルト引数はオブジェクトの静的型に基づいて決定されます(注:これは非仮想インターフェースパターンで回避できます)。
struct Base { virtual void f(int a = 7); }; struct Derived : Base { void f(int a) override; }; void m() { Derived d; Base& b = d; b.f(); // OK: calls Derived::f(7) d.f(); // Error: no default argument }
ローカル変数は、評価されない場合を除き、デフォルト引数では許可されません。
void f() { int n = 1; extern void g(int x = n); // error: local variable cannot be a default argument extern void h(int x = sizeof n); // OK as of CWG 2082 }
thisポインタはデフォルト引数では許可されません。
class A { void f(A* p = this) {} // error: this is not allowed };
非静的クラスメンバは、ポインタ-to-メンバを形成するために使用される場合や、メンバアクセス式で使用される場合を除き、デフォルト引数では許可されません(評価されない場合でも)。
int b; class X { int a; int mem1(int i = a); // error: non-static member cannot be used int mem2(int i = b); // OK: lookup finds X::b, the static member int mem3(int X::* i = &X::a); // OK: non-static member can be used int mem4(int i = x.a); // OK: in a member access expression static X x; static int b; };
デフォルト引数は、対応するパラメータに引数が指定されずに関数が呼び出されるたびに評価されます。関数パラメータは、評価されない場合を除き、デフォルト引数では許可されません。パラメータリストの早い段階に現れるパラメータはスコープ内にあることに注意してください。
int a; int f(int a, int b = a); // Error: the parameter a used in a default argument int g(int a, int b = sizeof a); // Error until resolving CWG 2082 // OK after resolution: use in unevaluated context is OK
デフォルト引数は関数型の一部ではありません。
int f(int = 0); void h() { int j = f(1); int k = f(); // calls f(0); } int (*p1)(int) = &f; int (*p2)() = &f; // Error: the type of f is int(int)
関数呼び出し演算子および添字演算子(C++23以降)以外の演算子関数はデフォルト引数を持つことができません。
class C { int operator++(int i = 0); // ill-formed int operator[](int j = 0); // OK since C++23 int operator()(int k = 0); // OK };
|
明示的オブジェクトパラメータはデフォルト引数を持つことができません。 struct S { void f(this const S& = S{}); }; // ill-formed |
(C++23から) |
[編集] 注記
パラメータ名がない場合、複合代入トークンを避けるためにスペースが必要な場合があります(最長一致を参照)。
void f1(int*=0); // Error, “*=” is unexpected here void g1(const int&=0); // Error, “&=” is unexpected here void f2(int* = 0); // OK void g2(const int& = 0); // OK void h(int&&=0); // OK even without spaces, “&&” is a token here
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 217 | C++98 | 非 テンプレートクラスのメンバ関数にデフォルト引数を追加できる |
禁止された |
| CWG 1344 | C++98 | メンバ関数のクラス外定義で追加されたデフォルト引数が、 それを特殊メンバ関数に変更する可能性がある |
禁止された |
| CWG 1716 | C++98 | デフォルト引数は関数が呼び出されるたびに評価されていた、 呼び出し元が引数を提供した場合でも |
対応するパラメータに引数が提供されない場合にのみ評価される 引数が提供されない場合にのみ 対応するパラメータに対して |
| CWG 2082 | C++98 | デフォルト引数はローカル変数の使用が禁止されていた および評価されないコンテキストで前のパラメータを使用することが |
評価されないコンテキスト 使用が許可された |
| CWG 2233 | C++11 | パラメータパックから展開されたパラメータは デフォルト引数を持つパラメータの後に現れることができなかった |
許可 |
| CWG 2683 | C++98 | クラステンプレートのネストされたクラスのメンバ関数のクラス外定義は デフォルト引数を持つことができた |
禁止された |