◐ Shell
clean mode source ↗

Declarações - cppreference.com

Declarações introduzem (ou re-introduzem) nomes ao programa C++. Cada tipo de entidade é declarado diferentemente. Definições são declarações que são suficientes para usar a entidade identificada pelo nome.

Uma declaração é uma das seguintes:

attr(opcional) declarator ;
attr (desde C++11) - sequência de qualquer número de atributos
declarator - Um declarador de função.
Esta declaração deve declarar um construtor, destrutor, ou função de conversão de tipo definido por usuário. Ela só pode ser usada como parte de uma declaração de template, especialização explícita, ou instanciação explícita.
  • block-declaration (uma declaração que pode aparecer dentro de um bloco), que, por sua vez, pode ser um das seguintes:

Declaração simples

Uma declaração simples é uma instrução que introduz, cria, e opcionalmente inicializa um ou vários identificadores, tipicamente variáveis.

decl-specifier-seq init-declarator-list(opcional) ; (1)
attr decl-specifier-seq init-declarator-list; (2)
attr (desde C++11) - sequência de qualquer número de atributos
decl-specifier-seq - sequência de especificadores (veja abaixo).
init-declarator-list - lista separada por vírgula de declaradores com inicializadores opcionais. init-declarator-list é opcional quando declarando uma classe/struct/union nomeada ou uma enumeração nomeada

Uma declaração de binding estruturado também é uma declaração simples. (desde C++17)

Especificadores

Especificadores de declaração (decl-specifier-seq) é uma sequência dos seguintes especificadores separados por whitespace, em qualquer ordem:

  • o especificador inline também é permitido em declarações de variável.
(desde C++17)
  • o especificador friend, permitido em declarações de classe e função.
  • o especificador constexpr, somente permitido em definições de variável, declarações de função e template de função, e na declaração de membros de dados estáticos de tipo literal.
(desde C++11)
  • o especificador consteval, somente permitido em declarações de função e template de função.
  • o especificador constinit, somente permitido em decaração de uma variável com duração de armazenamento estática ou de thread. No máximo um dos especificadores constexpr, consteval, e constinit é permitido aparecer numa decl-specifier-seq.
(desde C++20)
  • especificador de classe de armazenamento (register, static, thread_local (desde C++11), extern, mutable). Somente um especificador de classe de armazenamento é permitido, exceto que thread_local pode aparecer junto com extern ou static.
  • Especificadores de tipo (type-specifier-seq), uma sequência de especificadores que nomeia um tipo. O tipo de toda entidade introduzida pela declaração é este tipo, opcionalmente modificado pelo declarador (veja abaixo). Esta sequência de especificadores também é usada por type-id. Somente os seguintes especificadores são parte de type-specifier-seq, em qualquer ordem:
  • a palavra chave class, struct, ou union, seguida pelo identificador (opcionalmente qualificado), previamente definida como o nome de uma classe, struct, ou união.
  • a palavra chave class, struct, ou union, seguida por nome de template com argumentos de template (opcionalmente qualificado, opcionalmente usando desambiguador de template), previamente definida como o nome de um template de classe.
  • a palavra chave enum seguida pelo identificador (opcionalmente qualificado), previamente declarada como o nome de uma enumeração.
somente um especificador de tipo é permitido numa decl-specifier-seq, com as seguintes exceções:
- const pode ser combinado com qualquer especificador de tipo exceto ele mesmo.
- volatile pode ser combinado com qualquer especificador de tipo exceto ele mesmo.
- signed ou unsigned pode ser combinado com char, long, short, ou int.
- short ou long pode ser combinado com int.
- long pode ser combinado com double.
- long pode ser combinado com long.
(desde C++11)

Atributos podem aparecer em decl-specifier-seq, em tal caso eles se aplicam ao tipo determinado pelos especificadores precedentes.

O único especificador que é permitido aparecer duas vezes numa decl-specifier-seq é long (que pode aparecer duas vezes). Todas as outras repetições, tais como const static const, ou virtual inline virtual são erros.

(desde C++17)

Declaradores

init-declarator-list é uma sequência separada por vírgula de um ou mais init-declarators, que têm a seguinte sintaxe:

declarator initializer(opcional) (1)
declarator requires-clause (2) (desde C++20)

Cada init-declarator numa sequência de init-declarator S D1, D2, D3; é processado como se fosse uma declaração autônoma com os mesmos especificadores: S D1; S D2; S D3;.

Cada declarador introduz exatamente um objeto, referência, função, ou (para declarações de typedef) alias de tipo, cujo tipo é provido por decl-specifier-seq e opcionalmente modificado por operadores tais como & (referência a) ou [] (array de) ou () (função retornando) no declarador. Estes operadores podem ser aplicados recursivamente, como mostrado abaixo.

Um declarador (declarator) é um dos seguintes:

unqualified-id attr(opcional) (1)
qualified-id attr(opcional) (2)
... identifier attr(opcional) (3) (desde C++11)
* attr(opcional) cv(opcional) declarator (4)
nested-name-specifier * attr(opcional) cv(opcional) declarator (5)
& attr(opcional) declarator (6)
&& attr(opcional) declarator (7) (desde C++11)
noptr-declarator [ constexpr(opcional) ] attr(opcional) (8)
noptr-declarator ( parameter-list ) cv(opcional) ref(opcional) except(opcional) attr(opcional) (9)

1) O nome que é declarado.

4) Declarador de pointer: a declaração S * D; declara D como um pointer para um tipo determinado por decl-specifier-seq S.

6) Declarador de referência lvalue: a declaração S & D; declara D como uma referência lvalue ao tipo determinado por decl-specifier-seq S.

7) Declarador de referência rvalue: a declaração S && D; declara D coo uma referência rvalue ao tipo determinaddo por decl-specifier-seq S.

8) Declarador de array. noptr-declarator qualquer declarador válido, mas se ele começa com *, &, ou &&, ele tem de estar arrodeado por parênteses.

9) Declarador de função. noptr-declarator qualquer declaador válido, mas se ele comçea com *, &, ou &&, ele tem de estar arrodead por parêntenses. Note que o declarador de função no extremo mais externo pode terminar com o trailing return type opcional. (desde C++11)

Em todos os casos, attr é uma sequência de atributos. Quando aparecendo imediatamente depois do identificador, ele se aplica ao objeto sendo declarado.

cv é uma sequência de qualificadores const e volatile qualifiers, onde qualquer um desses qualificadores pode aparecer ao máximo uma vez na sequência.

Notas

Quando uma block-declaration aparece dentro de um bloco, e um identificador introduzido por uma declaração foi anteriorente declarado num outro ploco mais externo, a declaração mais externa é escondida pelo o resto do bloco.

Se uma declaração introduz uma variável com duração de armazenamento automática, ela é inicializada quando sua instrução de declaração é executada. Todas as variáveis automáticas declaradas num bloco são destruídas na saída do bloco (não importa como o bloco é saído: via exceção, goto, ou ao alcançar seu fim), em ordem oposta a sua ordem de inicialização.

Exemplos

#include <string>

class C {
    std::string membro; // decl-specifier-seq é "std::string"
                        // declarator é "membro"
} obj, *pObj(&obj);
// decl-specifier-seq é "class C { std::string membro; }"
// declarator "obj" define um objeto de tipo C
// declarator "*pObj(&obj)" declara e inicializa um pointer para C

int a = 1, *p = nullptr, f(), (*pf)(double);
// decl-specifier-seq é int
// declarator a = 1 define e inicializa uma variável de tipo int
// declarator *p = nullptr define e inicializa uma variável de tipo int*
// declarator (f)() declara (mas não define)
//                  uma função levando nenhuns argumentos e retornando int
// declarator (*pf)(double) define um pointer para função
//                  levando double e retornando int

int (*(*foo)(double))[3] = nullptr;
// decl-specifier-seq é int
// 1. declarator "(*(*foo)(double))[3]" é um declarador de array:
//    o tipo declarado é "array /declarador ninhado/ de 3 int"
// 2. o declarador ninhado é "(*(*foo)(double))", que é um declarador de pointer
//    o tipo declarado é "pointer /declarador ninhado/ para array de 3 int"
// 3. o declarador ninhado é "(*foo)(double)", que é um declarador de função
//    o tipo declarado é "função /declarador ninhado/ levando double e retornando
//        pointer para array de 3 int"
// 4. o declarador ninhado é "(*foo)" que é um declarador de pointer
          (parentesizado, como requerido por sintaxe de declarador de função).
//    o tipo declarado é "pointer /declarador ninhado/ para função levando double
//        e retornando pointer para array de 3 int"
// 5. o declarador ninhado é "foo", que é um identificador.
// A declaração declara o objeto foo de tipo "pointer para função levando double 
//     e retornando pointer para array de 3 int"
// O inicializador "= nullptr" provê o valor inicial deste pointer.

Veja também