Espacios de nombres
Variantes
Acciones

Declaraciones

De cppreference.com
< cpp‎ | language
 
 
 
 

Las declaraciones introducen (o reintroducen) nombres en un programa de C++. Cada tipo de entidad se declara de manera diferente. Las definiciones son declaraciones que son suficientes para usar la entidad identificada por el nombre.

Una declaración es una de las siguientes:

declarador atrib(opcional) ;
atrib (desde C++11) - secuencia de cualquier número de atributos
declarador - declarador de función.
Esta declaración tiene que declarar un constructor, destructor o una función de conversión de un tipo definido por el usuario. Solamente puede ser usada como parte de una declaración de plantilla, especialización explícita, o creación implícita.
  • declaración-de-bloque (una declaración que puede aparecer dentro de un bloque), que a su vez puede ser uno de los siguientes:

Contenido

[editar] Declaración simple

Una declaración simple es una instrucción que introduce, crea y opcionalmente inicializa uno o varios identificadores, típicamente variables.

sec-decl-espec lista-decl-inic(opcional) ; (1)
atrib sec-decl-especificadores lista-decl-inic; (2)
atrib (desde C++11) - Secuencia de cualquier número de atributos
sec-decl-especificadores - Secuencia de especificadores (véase abajo).
lista-decl-inic - Lista separada por comas de declaradores con inicializadores opcionales. La lista-decl-inic es opcional cuando se declara una class/struct/union con nombre o una enumeración con nombre.

Una declaración de vínculos estructurados también es una declaración simple. (desde C++17)

[editar] Especificadores

Los especificadores de declaración (sec-decl-especificadores) es una secuencia de los siguientes especificadores separados por espacios en blanco, en cualquier orden:

  • El especificador inline. También se permite en declaraciones de variables.
(desde C++17)
  • El especificador friend. Se permite en declaraciones de clases y funciones.
  • El especificador constexpr. Solamente se permite en definiciones de variables, funciones y declaraciones de plantillas de función, y la declaración de datos miembro estáticos de tipo de literal.
(desde C++11)
  • El especificador consteval. Solamente se permite en declaraciones de funciones y declaraciones de plantillas de función.
  • El especificador constinit. Solamente se permite en la declaración de una variable con duración estática o de almacenamiento de hilo. Se permite que, a lo más, uno de los especificadores constexpr, consteval y constinit aparezca en una sec-decl-especificadores.
(desde C++20)
  • especificador de clase de almacenamiento (register, static, thread_local (desde C++11), extern, mutable). Solamente se permite un especificador de clase de almacenamiento, excepto que thread_local puede aparecer junto con extern o static.
  • Especificadores de tipo (sec-espec-de-tipo). Una secuencia de especificadores que dan nombre a un tipo. El tipo de cada entidad introducida por la declaración es este tipo, opcionalmente modificado por el declarador (véase abajo). Esta secuencia de especificadores también se usa por type-id. Solamente los siguientes especificadores son parte de la sec-especificadores-de-tipo, en cualquier orden:
(desde C++11)
(desde C++17)
  • la palabra clave class, struct, o union, seguida de un identificador (opcionalmente calificado), previamente definido como el nombre de una clase, estructura o unión;
  • la palabra clave class, struct, o union, seguida por el nombre de la plantilla con argumentos de plantilla (opcionalmente calificada, opcionalmente usando un desambiguador de plantilla), previamente definida como el nombre de una plantilla de clase;
  • la palabra clave enum seguida del identificador (opcionalmente calificada), previamente declarada como el nombre de una enumeración;
solamente se permite un especificador de tipo en una sec-decl-especificadores, con las siguientes excepciones:
- const puede combinarse con cualquier especificador de tipo excepto consigo mismo;
- volatile puede combinarse con cualquier especificador de tipo excepto consigo mismo;
- signed o unsigned pueden combinarse con char, long, short, o int;
- short o long pueden combinarse con int;
- long puede combinarse con double;
- long puede combinarse con long.
(desde C++11)

Los atributos pueden aparecer en una sec-decl-especificadores, y en tal caso se aplican al tipo determinado por los especificadores precedentes.

El único especificador que se permite que aparezca dos veces en una sec-decl-especificadores es long (que puede aparecer dos veces). Todas las otras repeticiones, tales como const static const, o virtual inline virtual son errores.

(desde C++17)

[editar] Declaradores

Una lista-declaradores-init es una secuencia separada por comas de uno o más declaradores-init, que tienen la siguiente sintaxis:

declarador inicializador(opcional) (1)
declarador cláusula-requiere (2) (desde C++20)
declarador - El declarador
inicializador - Inicializador opcional (excepto donde se requiere, como al inicializar referencias u objetos constantes). Véase Inicialización para más detalles.
cláusula-requiere(C++20) - Una cláusula-requiere, que agrega una constricción a una declaración de función

Cada declarador-init en una secuencia declarador-init S D1, D2, D3; se procesa como si fuera una declaración independiente con los mismos especificadores: S D1; S D2; S D3;.

Cada declarador introduce exactamente un objeto, referencia, función o (para declaraciones typedef) alias de tipo, cuyo tipo se provee por una sec-decl-especificadores y opcionalmente se modifica por operadores tales como & (una referencia a) o [] (un array de) o () (una función que devuelve) en el declarador. Estos operadores pueden aplicarse recursivamente, como se muestra posteriormente.

Un declarador es uno de los siguientes:

id-no-calificado atrib(opcional) (1)
id-calificado atrib(opcional) (2)
... identificador atrib(opcional) (3) (desde C++11)
* atrib(opcional) cv(opcional) declarador (4)
especificador-de-nombre-anidado * atrib(opcional) cv(opcional) declarador (5)
& atrib(opcional) declarador (6)
&& atrib(opcional) declarador (7) (desde C++11)
declarador-noptr [ constexpr(opcional) ] atrib(opcional) (8)
declarador-noptr ( lista-de-parámetros ) cv(opcional) ref(opcional) except(opcional) atrib(opcional) (9)
1) El nombre que se declara.
2) Un declarador que utiliza un identificador calificado (id-calificado) define o redeclara un miembro de espacio de nombres previamente declarado o un miembro de clase.
4) Declarador de puntero: la declaración S * D; declara a D como un puntero al tipo determinado por la sec-decl-especificadores S.
5) Declaración de puntero a miembro: la declaración S C::* D; declara a D como un puntero a miembro de C del tipo determinado por la sec-decl-especificadores S. El especificador-de-nombre-anidado es una secuencia de nombres y operadores de resolución de ámbito ::
6) Declarador de referencia lvalue: la declaración S & D; declara a D como una referencia lvalue al tipo determinado por la sec-decl-especificadores S.
7) Declarador de referencia rvalue: la declaración S && D; declara a D como una referencia rvalue al tipo determinado por la sec-decl-especificadores S.
8) Declarador de array. declarador-noptr cualquier declarador válido, pero si comienza con *, &, o &&, tiene que estar rodeado por paréntesis.
9) Declarador de función. declarador-noptr cualquier declarador válido, pero si comienza *, &, o &&, tiene que estar rodeado por paréntesis. Observa que el declarador de función más externo puede terminar con el tipo de retorno opcional al final. (desde C++11)

En todos los casos, atrib es una secuencia opcional de atributos. Cuando aparece inmediatamente después del identificador, se aplica al objeto que se está declarando.

cv es una secuencia de calificadores const y volatile, donde cualquiera de los calificadores puede aparecer a lo más una vez en la secuencia.

[editar] Notas

Cuando una declaración-de-bloque aparece dentro de un bloque, y u identificador introducido por una declaración fue declarado previamente en un bloque externo, la declaración externa se oculta durante el resto del bloque.

Si una declaración introduce una variable con duración de almacenamiento automático, la variable se inicializa cuando su instrucción de declaración se ejecuta. Todas las variables automáticas declaradas en un bloque se destruyen a la salida del bloque (independientemente de cómo se sale del bloque: mediante una excepción, goto, o al alcanzar su fin), en el orden opuesto de su orden de inicialización.

[editar] Entender las declaraciones de C

Para entender una declaración de C sigue estas reglas:

  • Predecencia de alto a bajo:
    1. Los paréntesis se agrupan juntos como parte de la declaración.
    2. Operadores posfijos, tales como () (que indica una función) o [] (que indica un array).
    3. Operadores prefijos, tales como *, que indica un puntero.
  • Si ocurre un calificador-cv (p. ej. const o volatile) a la derecha del asterisco * (p. ej. int * const) entonces el calificador-cv se aplica al puntero (p. ej. int * const es un puntero const a int). De otra manera, si un calificador-cf ocurre a la izquierda de un asterisco y enseguida de un especificador de tipo, entonces el calificador-cv se aplica al tipo (p. ej. const int * o int const * se refieren ambos a un puntero a const int).

Para entender una declaración de C tal como int const * const * (*p[])(float), hacemos lo siguiente:

  1. Empieza con el nombre de la declaración (p. ej. p) y di "p un/una...". Sigue las reglas de precedencia dadas anteriormente en dirección externa desde el nombre, y aplica lo siguiente:
  2. si a la derecha inmediata existen corchetes (p. ej. []) entonces di "un "array de...".
  3. si a la derecha inmediate existe un paréntesis abierto (lista-de-param) (p. ej. () o (float, int)) entonces di "una función con parámetros (lista-de-param) que devuelve...".
  4. si a la izquierda inmediate existe un asterisco (y posiblemente calificadores-cv) entonces di "puntero(s) a..." (p. ej. for int const * const di "puntero const a const int).
  5. Repite (2) - (5) como sea necesario.

En nuestro ejemplo int const * const * (*p[])(float), "p es un array (por 2.) de punteros (por 4.) a funciones con parámetros (float) que devuelven (por 3.) un puntero a un puntero a const a const int," que significa que cada función a la que se apunta tiene un prototipo int const * const * funcname(float).

[editar] Ejemplos

#include <string>
 
class C {
    std::string member; // decl-specifier-seq is "std::string"
                        // declarator is "member"
} obj, *pObj(&obj);
// decl-specifier-seq is "class C { std::string member; }"
// declarator "obj" defines an object of type C
// declarator "*pObj(&obj)" declares and initializes a pointer to C
 
int a = 1, *p = nullptr, f(), (*pf)(double);
// decl-specifier-seq is int
// declarator a = 1 defines and initializes a variable of type int
// declarator *p = nullptr defines and initializes a variable of type int*
// declarator (f)() declares (but doesn't define)
//                  a function taking no arguments and returning int
// declarator (*pf)(double) defines a pointer to function
//                  taking double and returning int
 
int (*(*foo)(double))[3] = nullptr;
// decl-specifier-seq is int
// 1. declarator "(*(*foo)(double))[3]" is an array declarator:
//    the type declared is "/nested declarator/ array of 3 int"
// 2. the nested declarator is "(*(*foo)(double))", which is a pointer declarator
//    the type declared is "/nested declarator/ pointer to array of 3 int"
// 3. the nested declarator is "(*foo)(double)", which is a function declarator
//    the type declared is "/nested declarator/ function taking double and returning
//        pointer to array of 3 int"
// 4. the nested declarator is "(*foo)" which is a (parenthesized, as required by
//        function declarator syntax) pointer declarator.
//    the type declared is "/nested declarator/ pointer to function taking double
//        and returning pointer to array of 3 int"
// 5. the nested declarator is "foo", which is an identifier.
// The declaration declares the object foo of type "pointer to function taking double 
//     and returning pointer to array of 3 int"
// The initializer "= nullptr" provides the initial value of this pointer.