Namespaces
Variants

Declarations

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Объявления — это способ введения (или повторного введения) имен в программу на C++. Не все объявления действительно что-либо объявляют, и каждый вид сущности объявляется по-разному. Определения — это объявления, которые достаточны для использования сущности, идентифицируемой именем.

Объявление представляет собой одно из следующих:

  • Объявление атрибутов ( attr ; )
(начиная с C++11)
  • Пустое объявление ( ; )
  • Объявление функции без decl-specifier-seq :
attr  (необязательно) декларатор ;
attr - (since C++11) последовательность любого количества attributes
declarator - функциональный декларатор
Данное объявление должно объявлять конструктор, деструктор или пользовательскую conversion function . Оно может использоваться только как часть template declaration , explicit specialization , или explicit instantiation.
  • block-declaration (объявление, которое может находиться внутри блока ), которое, в свою очередь, может быть одним из следующих:
(начиная с C++11)
(начиная с C++20)
(начиная с C++11)
  • простая декларация

Содержание

Простое объявление

Простое объявление — это инструкция, которая вводит, создает и, опционально, инициализирует один или несколько идентификаторов, обычно переменных.

decl-specifier-seq init-declarator-list  (необязательно) ; (1)
attr decl-specifier-seq init-declarator-list ; (2) (начиная с C++11)
decl-specifier-seq - последовательность спецификаторов
init-declarator-list - разделённый запятыми список init-declarator ов (см. ниже)
attr - последовательность любого количества атрибутов


init-declarator-list может быть опущен только при объявлении именованного класса или именованного перечисления.

Объявление структурированной привязки также является простым объявлением.

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


Синтаксис init-declarator определяется следующим образом:

declarator initializer (1)
declarator requires-clause  (необязательно) contract-specs  (необязательно) (2)
1) Декларатор с инициализатором.
2) Декларатор без инициализатора.
declarator - a declarator
initializer - an initializer
requires-clause - (since C++20) a requires clause
contract-specs - (since C++26) a list of function contract specifiers


requires-clause может появляться только если declarator объявляет шаблонную функцию .

(since C++20)

contract-specs может появляться только если declarator объявляет функцию или шаблон функции.

(since C++26)

Спецификаторы

Спецификаторы объявления ( decl-specifier-seq ) представляет собой последовательность следующих разделенных пробелами спецификаторов в произвольном порядке:

  • спецификатор inline также разрешён в объявлениях переменных.
(начиная с C++17)
  • спецификатор friend , разрешённый в объявлениях классов и функций.
  • спецификатор constexpr , разрешённый только в определениях переменных, объявлениях функций и шаблонов функций, а также в объявлениях статических членов данных литерального типа.
(начиная с C++11)
  • спецификатор consteval , разрешённый только в объявлениях функций и шаблонов функций.
  • спецификатор constinit , разрешённый только в объявлении переменной со статической или поточной длительностью хранения. Не более одного из спецификаторов constexpr , consteval и constinit может присутствовать в decl-specifier-seq .
(начиная с C++20)
  • спецификатор класса хранения ( register , (до C++17) static , thread_local , (начиная с C++11) extern , mutable ). Допускается только один спецификатор класса хранения , за исключением того, что thread_local может появляться вместе с extern или static (начиная с C++11) .
  • Спецификаторы типа ( type-specifier-seq ), последовательность спецификаторов, которая задаёт тип. Тип каждой сущности, вводимой объявлением, является этим типом, опционально модифицированным декларатором (см. ниже). Эта последовательность спецификаторов также используется type-id . Только следующие спецификаторы являются частью type-specifier-seq , в любом порядке:
(начиная с C++11)
(начиная с C++26)
(начиная с C++17)
только один спецификатор типа разрешён в последовательности decl-specifier-seq, за следующими исключениями:
  • const может комбинироваться с любым спецификатором типа, кроме самого себя.
  • volatile может комбинироваться с любым спецификатором типа, кроме самого себя.
  • signed или unsigned могут комбинироваться с char , long , short , или int .
  • short или long могут комбинироваться с int .
  • long может комбинироваться с double .
  • long может быть объединен с long .
(начиная с C++11)

Атрибуты могут появляться в decl-specifier-seq , в этом случае они применяются к типу, определяемому предшествующими спецификаторами.

Повторения любого спецификатора в decl-specifier-seq , такие как const static const или virtual inline virtual являются ошибками , за исключением того, что long может появляться дважды (начиная с C++11) .

Деклараторы

Каждый init-declarator в init-declarator-list S D1, D2, D3 ; обрабатывается так, как если бы он был отдельным объявлением с теми же спецификаторами: S D1 ; S D2 ; S D3 ; .

Каждый декларатор вводит ровно один объект, ссылку, функцию или (для typedef-объявлений) псевдоним типа, чей тип задаётся decl-specifier-seq и опционально модифицируется операторами, такими как & (ссылка на) или [ ] (массив из) или ( ) (функция, возвращающая) в деклараторе. Эти операторы могут применяться рекурсивно, как показано ниже.

Объявитель declarator может быть одним из следующих:

unqualified-id attr  (необязательно) (1)
qualified-id attr  (необязательно) (2)
... identifier attr  (необязательно) (3) (начиная с C++11)
* attr  (необязательно) cv  (необязательно) declarator (4)
nested-name-specifier * attr  (необязательно) cv  (необязательно) declarator (5)
& attr  (необязательно) declarator (6)
&& attr  (необязательно) declarator (7) (начиная с C++11)
noptr-declarator [ constant-expression  (необязательно) ] attr  (необязательно) (8)
noptr-declarator ( parameter-list ) cv  (необязательно) ref   (необязательно) except  (необязательно) attr  (необязательно) (9)
( declarator ) (10)
1) Объявляемое имя .
2) Декларатор, использующий квалифицированный идентификатор ( qualified-id ), определяет или переобъявляет ранее объявленный член пространства имен или член класса .
3) Parameter pack , появляется только в объявлениях параметров .
4) Pointer declarator : объявление S * D ; объявляет D как указатель на тип, определяемый decl-specifier-seq S .
5) Объявление указателя на член : объявление S C :: * D ; объявляет D как указатель на член класса C типа, определяемого decl-specifier-seq S . nested-name-specifier представляет собой последовательность имён и операторов разрешения области видимости ::
6) Декларатор lvalue-ссылки : объявление S & D ; объявляет D как lvalue-ссылку на тип, определяемый decl-specifier-seq S .
7) Декларатор rvalue-ссылки : объявление S && D ; объявляет D как rvalue-ссылку на тип, определяемый decl-specifier-seq S .
8) Array declarator . noptr-declarator любой допустимый декларатор, но если он начинается с *, &, или &&, он должен быть окружен круглыми скобками.
9) Function declarator . noptr-declarator любой допустимый декларатор, но если он начинается с *, &, или &&, он должен быть окружён круглыми скобками. Он может заканчиваться необязательным завершающим возвращаемым типом. (since C++11)
10) Декларатор в скобках.

Во всех случаях, attr является необязательной последовательностью атрибутов . При появлении непосредственно после идентификатора, применяется к объявляемому объекту.

(since C++11)

cv представляет собой последовательность const и volatile квалификаторов, где каждый квалификатор может встречаться в последовательности не более одного раза.

Примечания

Когда block-declaration появляется внутри блока , и идентификатор, введённый объявлением, был ранее объявлен во внешнем блоке, внешнее объявление скрывается до конца блока.

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

Пример

Примечание: этот пример демонстрирует, как некоторые сложные объявления разбираются с точки зрения грамматики языка. Другие популярные мнемонические правила: правило спирали , чтение изнутри наружу , и объявление отражает использование . Также существует автоматический парсер на https://cdecl.org .

#include <type_traits>
struct S
{
    int member;
    // decl-specifier-seq is "int"
    // declarator is "member"
} obj, *pObj(&obj);
// decl-specifier-seq is "struct S { int member; }"
// declarator "obj" declares an object of type S
// declarator "*pObj" declares a pointer to S,
//     and initializer "(&obj)" initializes it
int i = 1, *p = nullptr, f(), (*pf)(double);
// decl-specifier-seq is "int"
// declarator "i" declares a variable of type int,
//     and initializer "= 1" initializes it
// declarator "*p" declares a variable of type int*,
//     and initializer "= nullptr" initializes it
// declarator "f()" declares (but doesn't define)
//     a function taking no arguments and returning int
// declarator "(*pf)(double)" declares a pointer to function
//     taking double and returning int
int (*(*var1)(double))[3] = nullptr;
// decl-specifier-seq is "int"
// declarator is "(*(*var1)(double))[3]"
// initializer is "= nullptr"
// 1. declarator "(*(*var1)(double))[3]" is an array declarator:
//    Type declared is: "(*(*var1)(double))" array of 3 elements
// 2. declarator "(*(*var1)(double))" is a pointer declarator:
//    Type declared is: "(*var1)(double)" pointer to array of 3 elements
// 3. declarator "(*var1)(double)" is a function declarator:
//    Type declared is: "(*var1)" function taking "(double)",
//    returning pointer to array of 3 elements.
// 4. declarator "(*var1)" is a pointer declarator:
//    Type declared is: "var1" pointer to function taking "(double)",
//    returning pointer to array of 3 elements.
// 5. declarator "var1" is an identifier.
// This declaration declares the object var1 of type "pointer to function
// taking double and returning pointer to array of 3 elements of type int"
// The initializer "= nullptr" provides the initial value of this pointer.
// C++11 alternative syntax:
auto (*var2)(double) -> int (*)[3] = nullptr;
// decl-specifier-seq is "auto"
// declarator is "(*var2)(double) -> int (*)[3]"
// initializer is "= nullptr"
// 1. declarator "(*var2)(double) -> int (*)[3]" is a function declarator:
//    Type declared is: "(*var2)" function taking "(double)", returning "int (*)[3]"
// ...
int main()
{
    static_assert(std::is_same_v<decltype(var1), decltype(var2)>);
}

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
CWG 482 C++98 деклараторы переобъявлений не могли быть квалифицированы квалифицированные деклараторы разрешены
CWG 569 C++98 одиночная точка с запятой не была допустимым объявлением это пустое объявление,
которое не имеет эффекта
CWG 1830 C++98 повторение спецификатора функции в decl-specifier-seq было разрешено повторение запрещено

Смотрите также

C documentation для Declarations