Espacios de nombres
Variantes
Acciones

Argumentos por defecto

De cppreference.com
< cpp‎ | language

Permite que se invoque una función sin proporcionar uno o más argumentos finales.

Esta traducción utiliza por defecto, valor por defecto, pero también es aceptable usar predeterminado, valor predeterminado.

Se indica mediante el uso de la siguiente sintaxis para un parámetro en la lista-de-parámetros de una declaración de función.

atrib(opcional)sec-decl-especificadoresdeclarador= inicializador (1)
atrib(opcional)sec-decl-especificadoresdeclarador-abstracto(opcional)= inicializador (2)

Los argumentos por defecto se usan en lugar de los argumentos finales faltantes en una llamada a la función:

void punto(int x =3, int y =4);   punto(1,2);// llama a punto(1,2) punto(1);// llama a punto(1,4) punto();// llama a punto(3,4)

En una declaración de función, después de un parámetro con un argumento por defecto, todos los parámetros posteriores deben

  • tener un argumento por defecto proporcionado en esta o en una declaración anterior del mismo ámbito
int x (int=1, int);// ERROR, asume que no hay una declaración previa de x   void f(int n, int k =1);void f(int n =0, int k);// de acuerdo: el valor por defecto de k proporcionado por la decl anterior en el mismo ámbito   void g(int, int=7);void h(){void g(int=1, int);// ERROR: no es el mismo ámbito}
* ... a menos que el parámetro se haya expandido desde un paquete de parámetros
template<class ...T>struct C {void f(int n =0, T...);}; C<int> c;// de acuerdo: instancia la declaración void C::f(int n = 0, int)
  • o ser un paquete de parámetros de función.
template<class...T>void h(int i =0, T... args);// de acuerdo
(desde C++11)

La elipsis no es un parámetro, por lo que puede seguir un parámetro con un argumento por defecto.

int g(int n =0, ...);// de acuerdo

Los argumentos por defecto solo están permitidos en las listas de parámetros de las declaraciones de funciones y expresiones lambda,(desde C++14) y no están permitidos en las declaraciones de punteros a funciones, referencias a funciones o en declaraciones typedef. Las listas de parámetros de plantilla utilizan una sintaxis similar para sus argumentos de plantilla por defecto.

Para funciones que no son de plantilla, se pueden agregar argumentos por defecto a una función que ya se declaró si la función se vuelve a declarar en el mismo ámbito. En el punto de una llamada a la función, los valores por defecto son una unión de los valores por defecto proporcionados en todas las declaraciones visibles para la función. Una redeclaración no puede introducir un valor por defecto para un argumento para el cual un valor por defecto ya es visible (incluso si el valor es el mismo). Una nueva declaración en un ámbito interno no adquiere los argumentos por defecto de ámbitos externos.

void f(int, int);// #1 void f(int, int=7);// #2 de acuerdo: agrega un valor por defecto   void h(){ f(3);// #1 y #2 están dentro del ámbito; hace una llamada a f(3,7)void f(int=1, int);// ERROR: las declaraciones de ámbito interno no adquieren valores por defecto}}   void m(){// comienza un nuevo ámbitovoid f(int, int);// declaración de ámbito interno; No tiene valores por defecto. f(4);// ERROR: no hay suficientes argumentos para llamar a f(int, int)void f(int, int=6); f(4);// de acuerdo: llama a f(4,6);void f(int, int=6);// ERROR: no se puede volver a declarar un valor por defecto en el mismo ámbito}   void f(int=1, int);// #3 de acuerdo: agrega un valor por defecto a #2   void n(){// comienza un nuevo ámbito  f();// #1, #2, y #3 están dentro del ámbito: llama a f(1, 7);}

Si se declara una función inline en diferentes unidades de traducción, los conjuntos acumulados de argumentos por defecto deben ser los mismos al final de cada unidad de traducción.

Si se declara una función no en línea en el mismo ámbito de espacio de nombres en diferentes unidades de traducción, los argumentos por defecto correspondientes deben ser los mismos si están presentes (pero algunos argumentos por defecto pueden estar ausentes en algunas unidades de traducción).

(desde C++20)

Si una declaración friend especifica un valor por defecto, debe ser una definición de función amiga, y no se permiten otras declaraciones de esta función en la unidad de traducción.

El using-declaration transfiere el conjunto de argumentos por defecto conocidos, y si se agregan más argumentos más tarde al espacio de nombres de la función, esos valores por defecto también son visibles en cualquier lugar donde la declaración de uso sea visible:

namespace N {void f(int, int=1);}using N::f;void g(){ f(7);// llama a f(7, 1); f();// ERROR}namespace N {void f(int=2, int);}void h(){ f();// llama a f(2, 1);}

Los nombres utilizados en los argumentos por defecto se buscan, se comprueban para accesibilidad y se vinculan en el punto de declaración, pero se ejecutan en el punto de la llamada a la función:

int a =1;int f(int);int g(int x = f(a));// la búsqueda de f encuentra ::f, la búsqueda a encuentra a ::a// el valor de ::a, que es 1 en este punto, no se usavoid h(){ a =2;// cambia el valor de ::a{int a =3; g();// llama a f(2), luego llama a g() con el resultado}}

Para una función miembro de una clase sin plantilla, los argumentos por defecto están permitidos en la definición fuera de clase y se combinan con los argumentos por defecto proporcionados por la declaración dentro del cuerpo de la clase. Si estos valores por defecto fuera de clase convertirían una función miembro en un constructor por defecto, de copia o movimiento, el programa está mal formado. Para las funciones miembro de las plantillas de clase, todos los valores por defecto se deben proporcionar en la declaración inicial de la función miembro.

class C {void f(int i =3);void g(int i, int j =99); C(int arg);// constructor no por defecto};void C::f(int i =3){// ERROR: ya es argumento por defecto}// especificado en el ámbito de la clasevoid C::g(int i =88, int j){// de acuerdo: en esta unidad de traducción,}// C::g se puede llamar sin argumento C::C(int arg =1){// ERROR: convierte esto en un constructor por defecto}

Los reemplazadores de funciones virtuales no adquieren los argumentos por defecto de las declaraciones de clase base, y cuando se realiza la llamada a la función virtual, los argumentos por defecto se deciden en función del tipo estático del objeto (nota: esto puede evitarse con el patrón interfaz no virtual).

struct Base {virtualvoid f(int a =7);};struct Derivada : Base {void f(int a) override;};void m(){ Derivada d; Base& b = d; b.f();// de acuerdo: llama a Derivada::f(7)  d.f();// ERROR: sin valor por defecto }

Las variables locales no están permitidas en los argumentos por defecto a menos que se use en un contexto no evaluado(desde C++14):

void f(){int n =1;externvoid g(int x = n);// ERROR: la variable local no puede ser un valor por defectoexternvoid h(int x = sizeof n);// de acuerdo a partir de CWG 2082}

El puntero this no está permitido en los argumentos por defecto:

class A {void f(A* p = this){}// ERROR: esto no está permitido};

Los miembros de clase no estáticos no están permitidos en los argumentos por defecto (incluso si no se evalúan), excepto cuando se usan para formar un puntero a miembro o en una expresión de acceso a miembro.

int b;class X {int a;int mem1(int i = a);// ERROR: no se puede usar un miembro no estáticoint mem2(int i = b);// de acuerdo: la búsqueda encuentra a X::b, el miembro estáticostaticint b;};

Los parámetros de función no están permitidos en los argumentos por defecto (incluso si no se evalúan)(hasta C++14) excepto si no están evaluados(desde C++14). Observa que los parámetros que aparecen anteriormente en la lista de parámetros están en ámbito:

int a;int f(int a, int b = a);// ERROR: el parámetro a utilizado en un argumento por defectoint g(int a, int b = sizeof a);// ERROR hasta CWG 2082// de acuerdo después de CWG 2082: el uso en contexto no evaluado está bien

Los argumentos por defecto no son parte del tipo de función

int f(int=0);void h(){int j = f(1);int k = f();// llama a f(0);}int(*p1)(int)=&f;int(*p2)()=&f;//ERROR: el tipo de f es int(int)


Si aparece una expresión lambda en un argumento por defecto, no puede capturar nada de forma explícita o implícita.

void f2(){int i =1;void g1(int=([i]{return i;})());// ERROR: captura algovoid g2(int=([i]{return0;})());// ERROR: captura algovoid g3(int=([=]{return i;})());// ERROR: captura algovoid g4(int=([=]{return0;})());// de acuerdo: sin capturavoid g5(int=([]{return sizeof i;})());// de acuerdo: sin captura}

Las funciones del operador no tendrán argumentos por defecto, excepto para el operador de llamada a función.

class C {int operator[](int i =0);// mal formadoint operator()(int x =0);// de acuerdo};

[editar]Informes de defectos

Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.

ID Aplicado a Comportamiento según lo publicado Comportamiento correcto
CWG 2082 C++14 Los argumentos por defecto tenían prohibido usar locales
en contexto no evaluado
Uso de contexto no evaluado permitido
close