Идентификаторы
Идентификатор — это последовательность произвольной длины, состоящая из цифр, символов подчёркивания, строчных и прописных латинских букв и большинства символов Unicode.
Синтаксис
Первым символом допустимого идентификатора должен быть один из следующих:
- прописные латинские буквы A–Z
- строчные латинские буквы a–z
- символ подчёркивания
- любой символ Unicode со свойством Unicode XID_Start
Любой другой символ допустимого идентификатора должен быть одним из следующих:
- цифры 0–9
- прописные латинские буквы A–Z
- строчные латинские буквы a–z
- символ подчёркивания
- любой символ Unicode со свойством Unicode XID_Continue
Списки символов со свойствами XID_Start и XID_Continue можно найти в файле DerivedCoreProperties.txt.
Идентификаторы чувствительны к регистру (строчные и прописные буквы различаются), и каждый символ имеет значение. Каждый идентификатор должен соответствовать форме нормализации C.
Примечание: поддержка идентификаторов Unicode в большинстве реализаций ограничена, например, gcc (до версии 10).
В объявлениях
Идентификатор можно использовать для именования объектов, ссылок, функций, перечислителей, типов, членов классов, пространств имён, шаблонов, специализаций шаблонов, наборов параметров(начиная с C++11), меток goto и других сущностей, за следующими исключениями:
- Идентификаторы, являющиеся ключевыми словами, нельзя использовать для других целей.
| (начиная с C++11) |
- Идентификаторы, являющиеся альтернативными представлениями некоторых операторов и знаков пунктуации, нельзя использовать для других целей.
| (начиная с C++11) |
- Идентификаторы, появляющиеся в виде токена или токена препроцессора (то есть не внутри user-defined-string-literal, например
operator ""id)(начиная с C++11) в одной из следующих форм, зарезервированы:- в глобальном пространстве имён — идентификаторы, начинающиеся с символа подчёркивания
- идентификаторы, содержащие два символа подчёркивания подряд или начинающиеся с символа подчёркивания, за которым следует прописная буква, за исключением следующих идентификаторов:
- предопределённые макросы (включая макросы проверки поддержки языковых возможностей)(начиная с C++20)
| (начиная с C++11) |
- следующие макросы, определённые в стандартной библиотеке:
- макросы библиотеки ввода-вывода в стиле C
_PRINTF_NAN_LEN_MAX, (начиная с C++26)_IOFBF,_IOLBFи_IONBF
| (начиная с C++11) |
| (начиная с C++20) |
Здесь «зарезервированы» означает, что заголовки стандартной библиотеки могут #define или объявлять такие идентификаторы для своих внутренних нужд, компилятор может предварительно определять нестандартные идентификаторы такого рода, а алгоритм декорирования имён может исходить из того, что некоторые из этих идентификаторов не используются. Если программист использует такие идентификаторы, программа некорректна; диагностика не требуется.
Кроме того, поведение не определено, если в единице трансляции выполнить #define или #undef для некоторых имён; подробности см. в разделе зарезервированные имена макросов.
Идентификаторы-зомби
Начиная с C++14 некоторые идентификаторы удалены из стандартной библиотеки C++. Они перечислены в списке имён-зомби.
Однако в определённом контексте эти идентификаторы по-прежнему зарезервированы в соответствии с предыдущими редакциями стандарта. Удалённые имена функций-членов нельзя использовать в качестве имён функциональных макросов, а другие удалённые имена членов нельзя использовать в переносимом коде в качестве имён объектных макросов.
В выражениях
Идентификатор, обозначающий переменную, функцию, специализацию концепта,(начиная с C++20) или перечислитель, можно использовать как выражение. Результатом выражения, состоящего только из идентификатора, является сущность, обозначенная этим идентификатором. Категория значения выражения — lvalue, если идентификатор обозначает функцию, переменную, объект параметра шаблона(начиная с C++20) или член данных, и rvalue(до C++11)prvalue(начиная с C++11) в противном случае (например, перечислитель является выражением типа rvalue(до C++11)prvalue(начиная с C++11), специализация концепта является bool prvalue(начиная с C++20)).
Тип
Тип выражения-идентификатора совпадает с типом обозначаемой им сущности.
| Существуют следующие исключения:
void f()
{
float x, &r = x;
[=]
{
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda
// is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float&
decltype((r)) r2 = y2; // r2 has type float const&
};
}
| (начиная с C++11) |
Неквалифицированные идентификаторы
Помимо надлежащим образом объявленных идентификаторов, в выражениях в той же роли можно использовать следующее:
- имя перегруженного оператора в функциональной записи, например
operator+илиoperator new; - имя пользовательской функции преобразования, например
operator bool;
| (начиная с C++11) |
- имя шаблона с последующим списком аргументов, например
MyTemplate<int>; - символ
~, за которым следует имя класса, например~MyClass;
| (начиная с C++11) |
| (начиная с C++26) |
Вместе с идентификаторами они называются выражениями с неквалифицированными идентификаторами.
Квалифицированные идентификаторы
Выражение с квалифицированным идентификатором — это выражение с неквалифицированным идентификатором, перед которым стоит оператор разрешения области видимости :: и которому может предшествовать последовательность из любого количества следующих элементов, разделённых операторами разрешения области видимости:
- имя пространства имён;
- имя класса;
| (начиная с C++11) |
| (начиная с C++26) |
Например, выражение std::string::npos — это выражение, обозначающее статический член npos класса string в пространстве имён std. Выражение ::tolower обозначает функцию tolower в глобальном пространстве имён. Выражение ::std::cout обозначает глобальную переменную cout в пространстве имён std, которое является пространством имён верхнего уровня. Выражение boost::signals2::connection обозначает тип connection, объявленный в пространстве имён signals2, которое объявлено в пространстве имён boost.
Ключевое слово template может присутствовать в квалифицированных идентификаторах, если это необходимо для устранения неоднозначности зависимых имён шаблонов.
Подробности поиска имён для квалифицированных идентификаторов см. в разделе квалифицированный поиск.
Преобразование в неявный доступ к члену
Если выражение-идентификатор E обозначает нестатический член некоторого класса C, не являющийся типом, и выполнены все следующие условия, E преобразуется в выражение доступа к члену класса this->E:
-
Eне является правым операндом оператора доступа к члену. - Если
Eявляется выражением с квалифицированным идентификатором,Eне является операндом оператора взятия адреса, не заключённым в скобки. - Выполнено одно из следующих условий:
-
Eявляется потенциально вычисляемым. -
Cявляется самым внутренним охватывающим классом вE. -
Cявляется базовым классом самого внутреннего охватывающего класса вE.
Это преобразование не применяется в контексте определения шаблона (см. раздел зависимые имена).
struct X
{
int x;
};
struct B
{
int b;
};
struct D : B
{
X d;
void func()
{
d; // OK, will be transformed into this->d
b; // OK, will be transformed into this->b
x; // Error: this->x is ill-formed
d.x; // OK, will be transformed into this->d.x
// instead of d.this->x or this->d.this->x
}
};
Имена
Имя — это использование одного из следующих элементов для обозначения сущности:
- идентификатор
- имя перегруженного оператора в функциональной записи (
operator+,operator new) - имя пользовательской функции преобразования (
operator bool)
| (начиная с C++11) |
- имя шаблона с последующим списком аргументов (
MyTemplate<int>)
Каждое имя вводится в программу посредством объявления. Имя, используемое более чем в одной единице трансляции, может обозначать одну и ту же или разные сущности в зависимости от связывания.
Когда компилятор встречает в программе неизвестное имя, он связывает его с объявлением, которое ввело это имя, посредством поиска имени, за исключением зависимых имён в объявлениях и определениях шаблонов (для таких имён компилятор определяет, обозначают ли они тип, шаблон или другую сущность; для этого может потребоваться явное устранение неоднозначности).
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применён к | Поведение согласно опубликованному стандарту | Правильное поведение |
|---|---|---|---|
| CWG 1440 | C++11 | выражения decltype перед :: могли обозначать любой тип | могут обозначать только типы класса или перечисления |
| CWG 1963 | C++11 | в идентификаторе можно было использовать символы, определяемые реализацией, кроме цифр, нецифровых символов и универсальных имён символов | запрещено |
| CWG 2521 | C++11 | идентификатор в user-defined-string-literal литерального оператора резервировался по обычным правилам | правила отличаются |
| CWG 2771 | C++98 |
&a не преобразовывался в &this->a в контекстах классов | он преобразуется |
| CWG 2777 | C++20 | тип выражения-идентификатора был неясен, если оно обозначало объект параметра шаблона | уточнено |
| CWG 2818 | C++98 | имена предопределённых макросов зарезервированы | они не зарезервированы |
См. также
| Документация по C по теме идентификаторы |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/identifiers