Если initializer-clauseв a указано, parameter-declarationэто initializer-clause используется как аргумент по умолчанию. Аргументы по умолчанию будут использоваться в вызовах, в которых отсутствуют конечные аргументы.
void point(int = 3, int = 4);
объявляет функцию, которая может быть вызвана с нулевым, одним или двумя аргументами типа int. Его можно вызвать любым из следующих способов:
point(1,2); point(1); point();
Последние два вызова эквивалентны point(1,4) и point(3,4)соответственно. ] — end example
Аргумент по умолчанию должен быть указан только в parameter-declaration-clause объявлении функции lambda-declarator или в template-parameter; в последнем случае initializer-clauseдолжен быть assignment-expression. Аргумент по умолчанию не должен указываться для пакета параметров. Если это указано в a parameter-declaration-clause, это не должно происходить в пределах a declarator или abstract-declarator a parameter-declaration.102
Для функций, не являющихся шаблоном, аргументы по умолчанию могут быть добавлены в более поздние объявления функции в той же области. Объявления в разных областях имеют совершенно разные наборы аргументов по умолчанию. То есть объявления во внутренних областях не получают аргументы по умолчанию из объявлений во внешних областях, и наоборот. В заданном объявлении функции каждый параметр, следующий за параметром с аргументом по умолчанию, должен иметь аргумент по умолчанию, предоставленный в этом или предыдущем объявлении, или должен быть пакетом параметров функции. Аргумент по умолчанию не должен переопределяться более поздним объявлением (даже с тем же значением). [ Example:
void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow // a parameter with a default argument void f(int, int); void f(int, int = 7); void h() { f(3); // OK, calls f(3, 7) void f(int = 1, int); // error: does not use default from surrounding scope } void m() { void f(int, int); // has no defaults f(4); // error: wrong number of arguments void f(int, int = 5); // OK f(4); // OK, calls f(4, 5); void f(int, int = 5); // error: cannot redefine, even to same value } void n() { f(6); // OK, calls f(6, 7) }
— end example ] Для данной встроенной функции, определенной в разных единицах трансляции, накопленные наборы аргументов по умолчанию в конце единиц трансляции должны быть одинаковыми; см [basic.def.odr]. Если объявление друга указывает выражение аргумента по умолчанию, это объявление должно быть определением и должно быть единственным объявлением функции или шаблона функции в блоке перевода.
Аргумент по умолчанию имеет те же семантические ограничения, что и инициализатор в объявлении переменной типа параметра с использованием copy-initialization семантики. Имена в аргументе по умолчанию связываются, и семантические ограничения проверяются в точке, где появляется аргумент по умолчанию. Поиск имени и проверка семантических ограничений для аргументов по умолчанию в шаблонах функций и в функциях-членах шаблонов классов выполняются, как описано в [temp.inst]. [ Example: В следующем коде g будет вызываться со значением f(2):
int a = 1; int f(int); int g(int x = f(a)); // default argument: f(::a) void h() { a = 2; { int a = 3; g(); // g(f(::a)) } }
— end example ] [ Note: В объявлениях функций-членов ищутся имена в аргументах по умолчанию, как описано в [basic.lookup.unqual]. Проверка доступа применяется к именам в аргументах по умолчанию, как описано в разделе [class.access]. ] — end note
За исключением функций-членов шаблонов классов, аргументы по умолчанию в определении функции-члена, которое появляется за пределами определения класса, добавляются к набору аргументов по умолчанию, предоставленных объявлением функции-члена в определении класса; программа имеет неправильный формат, если так объявлен конструктор по умолчанию ([class.ctor]), конструктор копирования или перемещения или оператор присваивания копирования или перемещения ([class.copy]). Аргументы по умолчанию для функции-члена шаблона класса должны быть указаны в начальном объявлении функции-члена в шаблоне класса. [ Example:
class C { void f(int i = 3); void g(int i, int j = 99); }; void C::f(int i = 3) {} // error: default argument already specified in class scope void C::g(int i = 88, int j) {} // in this translation unit, C::g can be called with no argument
— end example ]
Локальная переменная не должна появляться как потенциально оцениваемое выражение в аргументе по умолчанию. [ Example:
void f() { int i; extern void g(int x = i); // error extern void h(int x = sizeof(i)); // OK // ... }
— end example ]
[ Note: Ключевое слово this может не появляться в аргументе по умолчанию функции-члена; см [expr.prim.this]. [ Example:
class A {
void f(A* p = this) { } // error
};
— end example ] ] — end note
Аргумент по умолчанию оценивается каждый раз, когда функция вызывается без аргумента для соответствующего параметра. Параметр не должен отображаться как потенциально оцениваемое выражение в аргументе по умолчанию. Параметры функции, объявленной перед аргументом по умолчанию, находятся в области видимости и могут скрывать имена пространств имен и членов класса. [ Example:
int a; int f(int a, int b = a); // error: parameter a used as default argument typedef int I; int g(float I, int b = I(2)); // error: parameter I found int h(int a, int b = sizeof(a)); // OK, unevaluated operand
— end example ] Член нестатический не должен появляться в аргументе по умолчанию , если он не появляется , как id-expressionиз class member access expression или , если он не используется для формирования указателя на член ([expr.unary.op]). [ Example: Объявление X::mem1() в следующем примере неверно сформировано, поскольку не предоставляется объект для нестатического члена, X::a используемого в качестве инициализатора.
int b; class X { int a; int mem1(int i = a); // error: non-static member a used as default argument int mem2(int i = b); // OK; use X::b static int b; };
Однако объявление of X::mem2() имеет смысл, поскольку для доступа к статическому члену не требуется никаких объектов X::b. Классы, объекты и члены описаны в разделе [class]. ] Аргумент по умолчанию не является частью типа функции. [ — end example Example:
int f(int = 0); void h() { int j = f(1); int k = f(); // OK, means f(0) } int (*p1)(int) = &f; int (*p2)() = &f; // error: type mismatch
— end example ] Когда объявление функции вводится через a using-declaration, также становится известна любая информация аргумента по умолчанию, связанная с объявлением. Если после этого функция повторно объявляется в пространстве имен с дополнительными аргументами по умолчанию, дополнительные аргументы также становятся известными в любой момент после повторного объявления, где using-declaration находится в области видимости.
virtual function Вызов использует аргументы по умолчанию в объявлении виртуальной функции , определяемой статическим типом указателя или ссылки , обозначающего объект. Переопределяющая функция в производном классе не получает аргументы по умолчанию от функции, которую она переопределяет. [ Example:
struct A { virtual void f(int a = 7); }; struct B : public A { void f(int a); }; void m() { B* pb = new B; A* pa = pb; pa->f(); // OK, calls pa->B::f(7) pb->f(); // error: wrong number of arguments for B::f() }
— end example ]
Это означает, что аргументы по умолчанию не могут появляться, например, в объявлениях указателей на функции, ссылках на функции или typedef объявлениях.