Espacios de nombres
Variantes
Acciones

Declaración de función

De cppreference.com
< cpp‎ | language
 
 
Lenguaje C++
Temas generales
Control de flujo
Instrucciones de ejecución condicionales
Instrucciones de iteración (bucles)
Declaraciones de salto
Funciones
Declaración de funciones
Declaración de funciones lambda
Especificador inline
Especificación de excepciones(hasta C++20)
Especificador noexcept(C++11)
Excepciones
Espacios de nombres
Tipos
Especificadores
decltype(C++11)
auto(C++11)
alignas(C++11)
Especificadores de duración de almacenamiento
Inicialización
Expresiones
Representaciones alternas
Literales
Booleanos - Enteros - De punto flotante
De carácter - De cadena - nullptr(C++11)
Definidos por el usuario(C++11)
Utilidades
Atributos(C++11)
Tipos
Declaración de typedef
Declaración de alias de tipo(C++11)
Conversiones
Conversiones implícitas - Conversiones explícitas
static_cast - dynamic_cast
const_cast - reinterpret_cast
Asignación de memoria
Clases
Propiedades de funciones específicas de la clase
Funciones miembro especiales
Plantillas
Misceláneos
 

Una declaración de función introduce el nombre de la función y su tipo. Una definición de función asocia el nombre/tipo de la función con el cuerpo de función.

Contenido

[editar]Declaración de función

Las declaraciones de funciones pueden aparecer en cualquier ámbito. Una declaración de función en el ámbito de una clase introduce una función miembro de clase (a menos que se use el especificador friend), para más detalles véase funciones miembro y funciones amigas.

El tipo se función que se declara se compone del tipo de retorno (proporcionado por la secuencia-de-especificadores-de-declaración de la sintaxis de declaración) y el declarador de función.

noptr-declarador(lista-parámetros)cv(opcional)ref(opcional)excepción(opcional)atributos(opcional) (1)
noptr-declarador(lista-parámetros)cv(opcional)ref(opcional)excepción(opcional)atributos(opcional)->finalizador (2) (desde C++11)

(vea Declaraciones para otros formatos de sintaxis de declarador)

1) Sintaxis de declarador de función ordinario
2) Declaración del tipo de retorno final: el tipo de retorno final solo se permite en el declarador de función más externo. En este caso la secuencia-de-especificadores-de-declaración debe contener la palabra clave auto
noptr-declarador - cualquier declarador válido, pero si comienza con *, &, o &&, tiene que estar entre paréntesis.
lista-parámetros - que puede estar vacía, lista separada por comas de parámetros de función (ver abajo para más detalles)
atributos - (desde C++11) lista opcional de atributos. Estos atributos se aplican al tipo de la función, no a la función en sí. Los atributos de la función aparecen después del identificador dentro del declarador y se combinan con los atributos que aparecen al principio de la declaración, si los hay.
cv - calificación constante/volátil, solo se permite en declaraciones de funciones miembro no estáticas.
ref - (desde C++11) calificación ref, solo se permite en declaraciones de funciones miembro no estáticas
excepción -

especificación de excepción dinámica

(hasta C++11)

especificación de excepción dinámica
o especificación noexcept

(desde C++11)
(hasta C++17)

especificación noexcept

(desde C++17)

Tenga en cuenta que la especificación de excepción no es parte del tipo de función

(hasta C++17)
finalizador - Tipo de retorno final, útil si el tipo de retorno depende de los nombres de argumentos, como en template<class T, class U>auto suma(T t, U u)-> decltype(t + u); o es complicado, como en auto fpif(int)->int(*)(int)

Como se indica en Declaraciones, el declarador puede estar seguido de una cláusula requiere, que declara las restricticones asociadas a la función, que deben ser satisfechas para que la función pueda ser seleccionada por la resolución de sobrecarga. (ejemplo: void f1(int a) requires true;) Tenga en cuenta que la restricción asociada forma parte de la firma de la función, pero no forma parte del tipo de función.

(desde C++20)

Los declaradores de función se pueden mezclar con otros declaradores, donde secuencia-de-especificadores-de-declaración permite:

// declara un int, un int*, una función, y un puntero a funciónint a =1, *p =NULL, f(), (*pf)(double);// la secuencia-de-especificadores-de-declaración es int// el declarador f() declarar (pero no define)// una función sin argumentos y tipo de retorno int   struct S {virtualint f(char)const, g(int)&&;// declara dos funciones miembros no estáticasvirtualint f(char), x;// error de compilación: virtual (en la secuencia-de-especificadores-de-declaración)// solo se permite en la declaración de// funciones miembros no estáticas};

El uso de un tipo de objeto calificado volátil como tipo de parámetro o tipo de retorno está obsoleto.

(desde C++20)

El tipo de retorno de una función no puede ser un tipo función o array (pero puede ser un puntero o referencia a ellos).

Como en cualquier declaración, los atributos que aparecen antes de la declaración y los que aparecen inmediatamente después del identificador en el declarador se aplican a la entidad declarada o definida (en este caso, a la función):

[[noreturn]]void f [[noreturn]]();// correcto: ambos atributos de aplican a la función f

Sin embargo, los atributos que aparecen después del declarador (en la sintaxis anterior), se aplican al tipo de la función, no a la función en si:

void f()[[noreturn]];// error: este atributo no tiene efecto en la función misma
(desde C++11)

Como toda declaración, el tipo de la función func declarada como ret func(parámetros) es ret(parámetros) (excepto para la reescritura del tipo de parámetro que se describe a continuación): vea denominación de tipos.

Deducción de tipo devuelto

Si la secuencia-de-especificación-de-declaración de la declaración de la función contiene la palabra clave auto, se puede omitir el tipo de retorno final, y el compilador lo deduce del tipo de la expresión usada es la sentencia return. Si el tipo de retorno no usa decltype(auto), la deducción sigue las reglas de deducción de argumento de plantilla:

int x =1;auto f(){return x;}// el tipo de retorno es intconstauto& f(){return x;}// el tipo de retorno es const int&

Si el tipo de retorno es decltype(auto), el tipo de retorno es el que se obtendría si la expresión utilizada en la sentencia de retorno estuviera envuelta por decltype:

int x =1; decltype(auto) f(){return x;}// el tipo de retorno es int, como en decltype(x) decltype(auto) f(){return(x);}// el tipo de retorno es int&, como en decltype((x))

(nota: "const decltype(auto)&" es un error, decltype(auto) debe usarse solo)

Si hay múltiples sentencias de retorno, se debe deducir el mismo tipo en todas:

auto f(bool val){if(val)return123;// se deduce el tipo de retorno intelsereturn3.14f;// error: se deduce el tipo de retorno float}

Si no hay sentencia de retorno o si el argumento de la sentencia de retorno es una expresión vacía, el tipo de retorno declarado debe ser o bien decltype(auto), en cuyo caso el tipo deducido de retorno es void, o bien (que puede estar calificado cv) auto , en cuyo caso el tipo de retorno deducido es (con idéntica cualificación cv) void:

auto f(){}// devuelve voidauto g(){return f();}// devuelve voidauto* x(){}// error: no puede deducir auto* desde void

Una vez que se ve una sentencia de retorno en una función, el tipo de retorno deducido en esa sentencia se puede usar en el resto de la función, incluso en otras sentencias de retorno:

auto suma(int i){if(i ==1)return i;// el tipo de retorno de suma es intelsereturn suma(i -1)+ i;// correcto: el tipo de retorno de suma ya se conoce}

Si la sentencia de retorno usa una lista de inicialización entre paréntesis, no se permite la deducción:

auto func (){return{1, 2, 3};}// error

Las funciones virtualesy las corrutinas(desde C++20)no pueden usar la deducción de tipo de retorno:

struct F {virtualauto f(){return2;}// error};

Si una función usa la deducción de tipo de retorno, no puede ser redeclarada usando el tipo deducido, u otro tipo de deducción de tipo de retorno aunque se deduzca el mismo tipo:

auto f();// declarada, aún no definidaauto f(){return42;}// definida, el tipo de retorno es intint f();// error: no se puede usar el tipo deducido decltype(auto) f();// error: diferente forma de deducciónauto f();// correcot: re-declaración   template<typename T>struct A {friend T frf(T);};auto frf(int i){return i;}// no una amiga de A<int>

Las plantillas de función distintas de las funciones de conversión definidas por el usuario pueden usar el deducción del tipo de retorno. La deducción tiene lugar en la creación de instancias incluso si la expresión en la sentencia de retorno no es dependiente. Esta instanciación no se encuentra en un contexto inmediato para efectos de la SFINAE.

template<class T>auto f(T t){return t;}typedef decltype(f(1)) fint_t;// instancia f<int> para deducir el tipo de retorno   template<class T>auto f(T* t){return*t;}void g(){int(*p)(int*)=&f;}// instancias ambas f para determinar el tipo de retorno,// selecciona la segunda sobrecarga de la plantilla

Las especializaciones de las plantillas de función que usan la deducción del tipo de retorno deben usar los mismos marcadores del tipo de valor de retorno:

template<typename T>auto g(T t){return t;}// #1templateauto g(int);// correcto: tipo de retorno es int// template char g(char); // error: no coincide con plantilla   template<>auto g(double);// correcto: declaración adelantada con tipo de retorno desconocidotemplate<typename T> T g(T t){return t;}// correcto: no equivalente a #1   templatechar g(char);// correcto: ahora hay una plantilla coincidentetemplateauto g(float);// coincide con #1// auto h() { return g(42); } // error: ambiguo

Las declaraciones de creación de instancias explícitas no crean instancias de plantillas de funciones que usan la deducción del tipo de retorno:

template<typename T>auto f(T t){return t;}externtemplateauto f(int);// no instancia f<int>   int(*p)(int)= f;// crea una instancia de f<int> para determinar el tipo de retorno,// pero aún se requiere una definición de creación de// instancias explícita en algún lugar del programa
(desde C++14)

[editar]Lista de parámetros

La lista de parámetros determina los argumentos que se pueden especificar cunado se llama a una función. Es una lista separada por comas de declaraciones de parámetros, cada uno de los cuales tiene la siguiente sintaxis:

atributos(opcional)secuencia-de-especificadores-de-delaracióndeclarador (1)
atributos(opcional)secuencia-de-especificadores-de-delaracióndeclarador= inicializador (2)
atributos(opcional)secuencia-de-especificadores-de-delaracióndeclarador-abstracto(opcional) (3)
atributos(opcional)secuencia-de-especificadores-de-delaracióndeclarador-abstracto(opcional)= inicializador (4)
void (5)
1) Declara un parámetro (formal) con nombre. Para ver el significado de secuencia-de-especificadores-de-declaración y declarador, vea declaraciones.
int f(int a, int* p, int(*(*x)(double))[3]);
2) Declara un parámetro (formal) con nombre con un valor por defecto.
int f(int a =7, int* p = nullptr, int(*(*x)(double))[3]= nullptr);
3) Declara un parámetro sin nombre.
int f(int, int*, int(*(*)(double))[3]);
4) Declara un parámetro sin nombre con un valor por defecto.
int f(int=7, int*= nullptr, int(*(*)(double))[3]= nullptr);
5) Índica que la función no tiene parámetros, es exactamente igual que una lista de parámetros vacía: int f(void); y int f(); declaran la misma función. Tenga en cuenta que el tipo void (que puede estar cualificado cv) no se puede usar en una lista de parámetros: int f(void, int); y int f(constvoid); son errores (aunque se pueden usar tipos derivados como void*). En una plantilla, solo se pueden usar tipo void no dependiente (una función que toma un único parámetro de tipo T no puede llegar a ser una función sin parámetros si es instanciada con T = void).

Al final de la lista de parámetros puede aparecer una elipsis ...; esto declara una función variádica:

int printf(constchar* fmt ...);

Por compatibilidad con C89, puede aparecer una como opcional antes de la elipsis si la lista de parámetros tiene al menos un parámetro:

int printf(constchar* fmt, ...);// correcto, lo mismo que arrriba

Aunque secuencia-de-especificadores-de-declaración implica que pueden existir especificadores distintos de ñps especificadores de tipo, el único otro especificador permitido es registery auto(hasta C++11), y no tiene ningún efecto.

(hasta C++17)

Si cualquiera de los parámetros de la función usa un marcador de posición (auto o un Tipo concepto), la declaración de función es entonces una declaración de plantilla de función abreviada:

void f1(auto);// lo mismo que template<class T> void f(T)void f2(C1 auto);// lo mismo que template<C1 T> void f7(T), si C1 es un concepto
(desde C++20)

Los nombres de parámetros declarados en declaraciones de funciones son normalmente para propósitos de documentación. Se usan (pero siguen siendo opcionales) en las definiciones de funciones.

El tipo de cada parámetro de función en la lista de parámetros se determina a partir de las siguientes reglas:

1) Primero, la secuencia-de-especificadores-de-declaración y el declarador se combinan como en una declaración para determinar el tipo.
2) Si el tipo es "array de T" o "array de tamaño desconocido de T", se sustituye por el tipo "puntero a T"
3) Si el tipo es un tipo función F, se sustituye por el tipo "puntero a F"
4) Los calificadores cv de nivel superior se eliminan del tipo de parámetro (Este ajuste solo afecta al tipo de función, pero no modifica la propiedad del parámetro: int f(constint p, decltype(p)*); e int f(int, constint*); declaran la misma función)

Debido a estas reglas, las siguientes declaraciones de función declaran exactamente la misma función:

int f(char s[3]);int f(char[]);int f(char* s);int f(char*const);int f(char*volatile s);

Las siguientes declaraciones también declaran exactamente la misma función:

int f(int());int f(int(*g)());

El tipo de parámetro no puede ser un tipo de que incluya una referencia o un puntero a un array de límites desconocidos, incluidos punteros/array de niveles múltiples de dichos tipos, o un puntero a funciones cuyos parámetros sean de dichos tipos.

La elipsis que indica argumentos variádicos no necesita estar precedida por una coma, incluso si sigue a una elipsis que indica una expansión de paquete de parámetros, con lo que las siguientes plantillas de función son exactamente la misma:

template<typename... Args>void f(Args..., ...);template<typename... Args>void f(Args... ...);template<typename... Args>void f(Args......);

Un ejemplo de cuándo se podría usar esta declaración es la posible implementación de std::is_function.

#include <cstdio>   template<typename... Variadic, typename ...Args>constexprvoid invocar(auto(*fun)(Variadic......), Args... args){ fun(args...);}   int main(){ invocar(std::printf, "%dm•%dm•%dm = %d%s%c", 2,3,7, 2*3*7, "m³", '\n');}

Salida:

2m•3m•7m = 42m³
(desde C++11)

[editar]Definición de función

Una definición de función no miembro solamente puede aparecer en el ámbito de espacio de nombres (no hay funciones anidadas). Una definición de función miembro también puede aparecer en el cuerpo de una definición de clase. Tienen la siguiente sintaxis:

atributos(opcional)secuencia-de-especificadores-de-declaración(opcional)declaradorsecuencia-de-especificadores-virtuales(opcional)cuerpo-de-función

donde cuerpo-de-función es uno de los siguientes

inicializador-de-contructor(opcional)sentencia-compuesta (1)
bloque-función-try (2)
=delete; (3) (desde C++11)
=default; (4) (desde C++11)
1) cuerpo de función normal
2)bloque-función-try (que es un cuerpo de función normal dentro de un bloque try/catch)
3) definición de función eliminada explícitamente
4) definición de función predeterminada explícita, solo se permite pata funciones miembro especiales y funciones de operador de comparación(desde C++20)
atributos - (desde C++11) lista opcional de atributos. Estos atributos se combinan con los atributos posteriores al identificador en el declarador (vea el inicio de esta página), si hay.
secuencia-de-especificadores-de-declaración - el tipo de retorno con especificadores, como en la gramática de declaración
declarador - declarador de función, igual que en la gamática de declaración de función anterior. Al igual que con la declaración de función, puede ir seguida de una cláusula-requiere(desde C++20)
secuencia-de-especificadores-virtuales - (desde C++11)override, final,o su combinación en cualquier orden (solo se permite para funciones miembro no estáticas)
inicializador-de-contructor - lista de inicializadores de miembro, se permite solo en constructores
sentencia-compuesta - secuencia de sentencias encerradas entre llaves que constituye el cuerpo de la función
int max(int a, int b, int c){int m =(a > b)? a : b;return(m > c)? m : c;}   // la secuencia-de-despecificadores-de-declaración es "int"// el declarador es "max(int a, int b, int c)"// el cuerpo es { ... }

El cuerpo de la función es una sentencia compuesta (secuencia de cero o más sentencias encerradas por un par de llaves), que se ejecuta cuando se llama a la función.

Los tipos de los parámetros, así como el tipo de retorno de una función no pueden ser tipos claseincompletos a menos que la función se defina como eliminada(desde C++11). La comprobación de integridad se realiza en el contexto del cuerpo de la función, lo que permite que las funciones miembro devuelvan la clase en la que están definidas (o la clase que las contiene), incluso si en el punto de definición está incompleta (está completa en el cuerpo dela función).

Los parámetros declarados en el declarador de una definición de función están en el ámbito interno del cuerpo. Si no se usa un parámetro en el cuerpo de la función, no neceista ser nombrado (es suficiente con usar un declarador abstracto):

void escribir(int a, int)// no se usa el segundo parámtero{std::printf("a = %d\n", a);}

Aunque los calificadores cv de nivel superior en los parámetros se descartan en las declaraciones de función, modifican el tipo del parámetro como se ve en el cuerpo de un función:

void f(constint n)// declara una función de tipo void(int){// pero en el cuerpo, el tipo de n es const int}

Funciones eliminadas

Si, en vez de un cuerpo de función, se usa la sintaxis especial = delete ;, la función se define como eliminada. Cualquier uso de una función eliminada es un error (el programa no compilará). Esto incluye llamadas, ya sean explícitas (con un operador de llamada a función) o implícitas (una llamada al operador sobrecargado eliminado, función miembro especial, función de asignación, etc), construir un puntero o puntero a miembro a una función eliminada, e incluso el uso de una función eliminada en una expresión no evaluada. Sin embargo, se permite el uso ODR implícito de una función miembro virtual no pura que se elimina.

Si la función está sobrecargada, primero tiene lugar la resolución de sobrecarga, y le programa está mal formado solamente si se seleccionó la función eliminada:

struct alguntipo {void*operator new(std::size_t)= delete;void*operator new[](std::size_t)= delete;}; alguntipo* p = new alguntipo;// error: intenta llamar al eliminado alguntipo::operator new

La definición de eliminación de una función debe ser la primera declaración en la unidad de traducción: una función declarada previamente no se puede redeclarar como eliminada:

struct alguntipo { alguntipo();}; alguntipo ::alguntipo()= delete;// error: debe ser eliminada en la primera declaración

__func__

Dentro del cuerpo de la función, la variable predefinida local a la función __func__ se define como si fuera

staticconstchar __func__[]="nombre-de-función";

Esta variable tiene ámbito de bloque y duración de almacenamiento estático:

struct S { S(): s(__func__){}// correcto: la lista de incializadores es parte de cuerpo de la funciónconstchar* s;};void f(constchar* s = __func__);// error: la lista de parámetros es parte del declarador
#include <iostream>   void Foo(){std::cout<< __func__ <<' ';}   struct Bar { Bar(){std::cout<< __func__ <<' ';} ~Bar(){std::cout<< __func__ <<' ';}struct Pub { Pub(){std::cout<< __func__ <<' ';}};};   int main(){ Foo(); Bar bar; Bar::Pub pub;}

Posible salida:

Foo Bar Pub ~Bar
(desde C++11)

[editar]Notas

En caso de ambigüedad entre una declaración de variable usando la sintaxis de incialización directa y una declaración de función, el compilador siempre elige la declaración de función; vésae inicialización directa.

[editar]Ejemplo

#include <iostream>#include <string>   // función simple con un argumento por defecto, sin valor devueltovoid f0(conststd::string& arg ="mundo!"){std::cout<<"¡Hola, "<< arg <<'\n';}   // la declaración está en el ámbito de espacio de nombres (archivo)// (la definición se proporciona más tarde)int f1();   // función que devuelve un puntero a f0, estilo pre-C++11void(*fp03())(conststd::string&){return f0;}   // función que devuelve un puntero a f0, con tipo de retorno final C++11 auto fp11()->void(*)(conststd::string&){return f0;}   int main(){ f0(); fp03()("prueba!"); fp11()("otra vez!");int f2(std::string)noexcept;// declaración en ámbito de funciónstd::cout<<"f2(\"mal\"): "<< f2("mal")<<'\n';std::cout<<"f2(\"42\"): "<< f2("42")<<'\n';}   // función no miembro simple que devuelve intint f1(){return007;}   // función con una especificación de excepción y una bloque tryint f2(std::string str)noexcepttry{returnstd::stoi(str);}catch(conststd::exception& e){std::cerr<<"¡stoi() falla!\n";return0;}

Posible salida:

¡stoi() falla! ¡Hola, mundo! ¡Hola, prueba! ¡Hola, otra vez! f2("mal"): 0 f2("42"): 42

[editar]Informe de errores

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 135 C++98 funciones miembros definidas en una clase no pueden tener un parámetro
de o devolver su propia clase porque es incompleta
se permite
CWG 393 C++98 tipos que incluyen punteros/referencias a
un array de límites desconocidos no pueden ser parámetros
se permiten dichos tipos
CWG 452 C++98 la lista de inicializadores de miembro no es parte del cuerpo de la función se hace parte del cuerpo
de la función al modificar la
sintaxis de la definición de función
CWG 577 C++98 se podía usar el tipo void dependiente
para declarar una función sin parámetros
solo se permite void no dependiente
CWG 1394 C++11 la función eliminada no podía devolver un tipo incompleto se permite el tipo de retorno incompleto

[editar]Véase también

Documentación de C para Declaración de funciones
close