Spec-Zone.ru › C++

Значения по умолчанию для аргументов

Позволяет вызывать функцию без указания одного или нескольких последующих аргументов.

Указывается с помощью следующего синтаксиса для параметра в списке параметров объявления функции.

attr (необязательно) decl-specifier-seq declarator = initializer (1)
attr (необязательно) decl-specifier-seq abstract-declarator (необязательно) = 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);
}

Если функция inline объявлена в разных единицах трансляции, совокупности значений по умолчанию должны быть одинаковыми в конце каждой единицы трансляции.

Если функция без inline объявлена в одной и той же области видимости пространства имен в разных единицах трансляции, соответствующие значения по умолчанию должны быть одинаковыми, если они присутствуют (но некоторые значения по умолчанию могут отсутствовать в некоторых TU).

(с C++20)

Если объявление friend указывает значение по умолчанию, это должно быть определение дружественной функции, и другие объявления этой функции в единице трансляции не допускаются.

Объявление using-declarations сохраняет набор известных значений по умолчанию, и если позже добавляются другие значения по умолчанию в пространство имен функции, эти значения по умолчанию также будут видны везде, где видно объявление 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
    }
}

Для членной функции нешаблонного класса значения по умолчанию разрешены в определении вне класса и объединяются со значениями по умолчанию, предоставленными в объявлении внутри тела класса. Если эти значения по умолчанию вне класса сделают членскую функцию конструктором по умолчанию или оператором копирования/перемещения (что делает вызов неоднозначным), программа некорректна. Для членских функций шаблонных классов все значения по умолчанию должны быть предоставлены в начальном объявлении членской функции.

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
};

Нестатические члены класса не разрешены в значениях по умолчанию (даже если они не оцениваются), за исключением случаев использования для формирования указателя на член или в выражении доступа к члену:

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)

Функции операторов не могут иметь значений по умолчанию, за исключением оператора вызова функции:

class C
{
    int operator[](int i = 0); // ill-formed
    int operator()(int x = 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 определения вне класса членских функций вложенных классов шаблонов классов могли иметь значения по умолчанию запрещено

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/default_arguments

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API