Declarations
Объявления — это способ введения (или повторного введения) имен в программу на C++. Не все объявления действительно что-либо объявляют, и каждый вид сущности объявляется по-разному. Определения — это объявления, которые достаточны для использования сущности, идентифицируемой именем.
Объявление представляет собой одно из следующих:
- Определение функции
- Объявление шаблона (включая Частичную специализацию шаблона )
- Явное инстанцирование шаблона
- Явная специализация шаблона
- Определение пространства имён
- Спецификация компоновки
|
(начиная с 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) | ||||||||
| 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 ) представляет собой последовательность следующих разделенных пробелами спецификаторов в произвольном порядке:
-
спецификатор
typedef. Если присутствует, вся декларация является typedef-декларацией , и каждый декларатор вводит новое имя типа, а не объект или функцию. -
спецификаторы функций (
inline,virtual,explicit), разрешены только в декларациях функций .
|
(начиная с C++17) |
-
спецификатор
friend, разрешённый в объявлениях классов и функций.
|
(начиная с C++11) |
|
(начиная с 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) |
-
-
- ранее объявленное имя класса (опционально квалифицированное )
- ранее объявленное имя перечисления (опционально квалифицированное )
- ранее объявленное typedef-имя или псевдоним типа (начиная с C++11) (опционально квалифицированное )
- имя шаблона с аргументами шаблона (опционально квалифицированное , опционально с использованием дисквалификатора шаблона )
-
|
(начиная с C++17) |
-
-
- ключевое слово class , struct , или union , за которым следует идентификатор (опционально квалифицированный ), ранее определённый как имя класса.
- ключевое слово class , struct , или union , за которым следует имя шаблона с аргументами шаблона (опционально квалифицированное , опционально с использованием template дисамбигуатора ), ранее определённое как имя шаблона класса.
- ключевое слово enum , за которым следует идентификатор (опционально квалифицированный ), ранее объявленный как имя перечисления.
-
-
только один спецификатор типа разрешён в последовательности decl-specifier-seq, за следующими исключениями:
- const может комбинироваться с любым спецификатором типа, кроме самого себя.
- volatile может комбинироваться с любым спецификатором типа, кроме самого себя.
- signed или unsigned могут комбинироваться с char , long , short , или int .
- short или long могут комбинироваться с int .
- long может комбинироваться с double .
|
(начиная с 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) | ||||||||
D
как указатель на тип, определяемый
decl-specifier-seq
S
.
D
как указатель на член класса
C
типа, определяемого
decl-specifier-seq
S
.
nested-name-specifier
представляет собой
последовательность имён и операторов разрешения области видимости
::
D
как lvalue-ссылку на тип, определяемый
decl-specifier-seq
S
.
D
как rvalue-ссылку на тип, определяемый
decl-specifier-seq
S
.
|
Во всех случаях, attr является необязательной последовательностью атрибутов . При появлении непосредственно после идентификатора, применяется к объявляемому объекту. |
(since C++11) |
cv представляет собой последовательность const и volatile квалификаторов, где каждый квалификатор может встречаться в последовательности не более одного раза.
|
Этот раздел не завершён
Причина: объяснить правила скрытия имён в объявлениях; как объявление переменной/функции скрывает класс (но не typedef) с тем же именем |
Примечания
Когда 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
|