Spec-Zone.ru › C++

Аргументы по умолчанию

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

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

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

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

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

(начиная с C++20)

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

Объявления 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
};

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

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
    consteval int mem5(std::meta::info r = ^^a); // OK since C++26: as a reflection
    
    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 определения функций-членов вложенных классов шаблонов классов
вне класса могли содержать аргументы по умолчанию
запрещено

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

Spec-Zone.ru

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