Пространства имён
Варианты
Действия

Объявления

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
if
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений (до C++17*)
Спецификатор noexcept (C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype (C++11)
auto (C++11)
alignas (C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr (C++11)
Определяемые пользователем (C++11)
Утилиты
Атрибуты (C++11)
Types
Объявление typedef
Объявление псевдонима типа (C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
��ыделение памяти
Классы
Свойства функции класса
explicit (C++11)
static
Специальные функции-элементы
Шаблоны
Разное
 
Обьявления
Объявления
ссылка
указатель
массив
Block declarations
простое объявление
объявление структурных привязок (C++17)
объявление псевдонимов(C++11)
объявление псевдонимов пространств имён
using-declaration
директива using
объявление static_assert (C++11)
определение asm
объявление непрозрачного enum(C++11)
Другие объявления
определение пространств имён
объявление функции
объявление шаблона класса
объявление шаблона функции
явное инстанцирование шаблона(C++11)
явная специализация шаблона
спецификация связывания
объявление атрибута (C++11)
пустое объявление
 

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

Существуют следующие объявления:

(начиная с C++11)
  • Пустое объявление (;)
  • Объявление функции без последовательности-спецификаторов-объявления:
атрибуты (необязательно) декларатор ;
атрибуты (начиная с C++11) последовательность любого числа атрибутов
декларатор объявление функции
Это объявление должно содержать конструктор, деструктор, или определённый пользователем тип функции преобразования. Это может быть использовано, как часть объявления шаблона, явной специализации шаблона, явного создания экземпляра шаблона.
  • объявление-блока (объявление, которое может появиться внутри блока), который, в свою очередь, может быть одним из следующего:
(начиная с C++11)
(начиная с C++20)
(начиная с C++11)
  • простое объявление

Содержание

[править] Простое объявление

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

последовательность-спецификаторов-объявления список-инициализации-деклараторов (необязательно) ; (1)
атрибуты последовательность-спецификаторов-объявления список-инициализации-деклараторов; (2)
атрибуты (начиная с C++11) последовательность любого числа атрибутов
последовательность-спецификаторов-объявления последовательность спецификаторов (смотрите ниже).
список-инициализации-деклараторов разделённый запятыми список объявлений с необязательными инициализаторами. список-инициализации-деклараторов необязателен, когда объявление, это именованные класс/структура/объединение или именованное перечисление

Определение структурных привязок так же простое объявление. (начиная с C++17)

[править] Спецификаторы

Объявленные спецификаторы, (последовательность-спецификаторов-объявления) это последовательность следующих, разделённых пробельными символами, спецификаторов в любой последовательности:

  • спецификатор typedef. Если присутствует, то это законченное объявление, состоящее из объявления typedef и объявлений, каждое из которых вводит новое имя типа, но не объект или функцию.
  • спецификаторы функций (inline, virtual, explicit), разрешены только в объявлениях функций.
  • спецификатор inline так же разрешён в объявлении переменных.
(начиная с C++17)
  • спецификатор friend, разрешён в объявлении класса или функции.
  • спецификатор constexpr, разрешён только в объявлении переменных, объявлении функций и шаблонов функций, а так же в объявлении статических членов данных и литеральных типов.
(начиная с C++11)
  • спецификатор consteval, разрешён только в объявлениях функций и шаблонов функций.
  • спецификатор constinit, разрешён только в объявлении переменной со статическим или потоковым классом памяти. Разрешён только один спецификатор constexpr, consteval и constinit в последовательности-спецификаторов-объявления.
(начиная с C++20)
  • спецификатор класса памяти (register (до C++17), static, thread_local (начиная с C++11), extern, mutable). Разрешён только один спецификатор памяти, исключая thread_local, который можно использовать вместе с extern или static (начиная с C++11).
  • Спецификаторы типов (последовательность-спецификаторов-типов), спецификаторы типов, которые являются именами типов. Тип каждой сущности, введённой объявлением, это тип, необязательно модифицированный объявлением (смотрите ниже). Последовател��ность спецификаторов так же используется в type-id. Только следующие спецификаторы являются частью последовательности-спецификаторов-типа, в любом порядке:
(начиная с C++11)
(начиная с C++17)
  • ключевое слово class, struct или union, с последующим идентификатором (необязательно полным), ранее определённым, как имя класса, структуры или объединения.
  • ключевое слово class, struct или union, с последующим именем шаблона с аргументами шаблона (необязательно полным, необязательно использующим неоднозначности шаблона), ранее определённым, как имя класса шаблона.
  • ключевое слово enum с последующим идентификатором (необязательно полным), ранее определённым, как имя перечисления.
только один тип спецификатора разрешён в последовательности-спецификаторов-объявления, со следующими исключениями:
- const может сочетаться с любым типом спецификатора, исключая самого себя.
- volatile может сочетаться с любым типом спецификатора, исключая самого себя.
- signed или unsigned могут сочетаться с char, long, short или int.
- short или long могут сочетаться с int.
- long может сочетаться с double.
- long может сочетаться с long.
(начиная с C++11)

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

Спецификатор, который может появляться дважды в последовательности-спецификаторов-объявления это long (который может появляться дважды). Все другие повторения, такие как const static const, или virtual inline virtual являются ошибками.

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

[править] Объявления

список-деклараторов-инициализации это разделённая запятыми последовательность одного или более деклараторов-инициализации, которая имеет следующий синтаксис:

декларатор инициализатор (необязательно) (1)
декларатор предложение-requires (2) (начиная с C++20)
декларатор объявление
инициализатор необязательный инициализатор (за исключением случаев, когда он требуется, таких как инициализация ссылок или константных объектов). Для получения подробностей смотрите Инициализация.
предложение-requires предложение requires, которое добавляет ограничения к объявлению функции

Каждый декларатор-инициализации в последовательности инициализирующих объявлений S D1, D2, D3; обрабатывается, как если бы это было автономное объявление с теми же спецификаторами: S D1; S D2; S D3;.

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

декларатор это одно из следующего:

неполный-id атрибуты (необязательно) (1)
полный-id атрибуты (необязательно) (2)
... идентификатор атрибуты (необязательно) (3) (начиная с C++11)
* атрибуты (необязательно) cv (необязательно) декларатор (4)
спецификатор-вложенного-имени * атрибуты (необязательно) cv (необязательно) декларатор (5)
& атрибуты (необязательно) декларатор (6)
&& атрибуты (необязательно) декларатор (7) (начиная с C++11)
декларатор-не-указатель [ constexpr (необязательно) ] атрибуты (необязательно) (8)
декларатор-не-указатель ( список-параметров ) cv (необязательно) ссылка (необязательно) except (необязательно) атрибуты (необязательно) (9)
1) Объявленное имя.
2) Объявление, которое использует полный идентификатор (полный-id), объявляет или переопределяет ранее объявленный член пространства имён или член класса.
4) Объявление указателя: объявление S * D;, которое объявляет D как указатель на тип, определённый как последовательность-спецификаторов-объявления S.
5) Указатель на объявление элемента: объявление S C::* D;, объявляет D как указатель на элемент типа C, определённого как последовательность-спецификаторов-объявления S. спецификатор-вложенного-имени это последовательность имён и операторов разрешения области видимости ::
6) Объявление lvalue ссылки: объявление S & D; объявляет D как lvalue ссылку на тип, определённый как последовательность-спецификаторов-объявления S.
7) Объявление rvalue ссылки: объявление S && D; объявляет D как rvalue ссылку на тип, определённый как последовательность-спецификаторов-объявления S.
8) Объявление массива. декларатор-не-указатель любое допустимое объявление, но если оно начинается с *, &, или &&, и окружено круглыми скобками.
9) Объявление функции. декларатор-не-указатель любое допустимое объявление, если оно начинается с *, & или &&, и окружено круглыми скобками. Обратите внимание, что объявление внешней функции может, необязательно, заканчиваться типом возвращаемого значения. (начиная с C++11)

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

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

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

[править] Примечание

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

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

[править] Примеры

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

#include <type_traits>
 
struct S
{
    int member;
    // последовательность-деклараторов-объявления равна "int"
    // декларатор является "элементом"
 
} obj, *pObj(&obj);
// последовательность-деклараторов-объявления равна "struct S { int member; }"
// декларатор "obj" объявляет объект типа S
// декларатор "*pObj" объявляет указатель на S,
//     и инициализатор "(&obj)" инициализирует его
 
int i = 1, *p = nullptr, f(), (*pf)(double);
// последовательность-деклараторов-объявления равна "int"
// декларатор "i" объявляет переменную типа int,
//     и инициализатор "= 1" инициализирует её
// декларатор "*p" объявляет переменную типа int*,
//     и инициализатор "= nullptr" инициализирует её
// декларатор "f()" объявляет (но не определяет)
//     функцию, не принимающую аргументов и возвращающую int
// декларатор "(*pf)(double)" объявляет указатель на функцию,
//     принимающую double и возвращающую int
 
int (*(*var1)(double))[3] = nullptr;
// последовательность-деклараторов-объявления равна "int"
// декларатор "(*(*var1)(double))[3]"
// инициализотор "= nullptr"
 
// 1. декларатор "(*(*var1)(double))[3]" является декларатором массива:
//    Объявленный тип: "(*(*var1)(double))" массив из 3 элементов
// 2. декларатор "(*(*var1)(double))" является декларатором указателя:
//    Объявленный тип: "(*var1)(double)" указатель на массив из 3 элементов
// 3. декларатор "(*var1)(double)" является декларатором функции:
//    Объявленный тип: функция "(*var1)", принимающая "(double)",
//    возвращает указатель на массив из 3 элементов.
// 4. декларатор "(*var1)" является декларатором указателя:
//    Объявленный тип: "var1" указатель на функцию, принимающую "(double)",
//    возвращающую указатель на массив из 3 элементов.
// 5. декларатор "var1" является идентификатором.
// Это объявление объявляет объект var1 типа "указатель на функцию,
// принимающую double и возвращающую указатель на массив из 3 элементов типа int"
// Инициализатор "= nullptr" предоставляет начальное значение этого указателя.
 
// Альтернативный синтаксис С++11:
auto (*var2)(double) -> int (*)[3] = nullptr;
// последовательность-деклараторов-объявления равна "auto"
// декларатор "(*var2)(double) -> int (*)[3]"
// инициализотор "= nullptr"
 
// 1. декларатор "(*var2)(double) -> int (*)[3]" является декларатором функции:
//    Объявленный тип: функция "(*var2)", принимающая "(double)", возвращающая "int (*)[3]"
// ...
 
int main()
{
    static_assert(std::is_same_v<decltype(var1), decltype(var2)>);
}

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

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

[править] Смотрите также

Документация C по Объявления