11 Declarators [dcl.decl]

11.3 Meaning of declarators [dcl.meaning]

11.3.6 Default arguments [dcl.fct.default]

Если initializer-clauseв a указано, parameter-declarationэто initializer-clause используется как аргумент по умолчанию. Аргументы по умолчанию будут использоваться в вызовах, в которых отсутствуют конечные аргументы.

[ Example: Декларация

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 exampleExample:

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 объявлениях.