Spec-Zone.ru › C++

Идентификаторы

Идентификатор — это последовательность произвольной длины, состоящая из цифр, символов подчёркивания, строчных и прописных латинских букв и большинства символов 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 и других сущностей, за следующими исключениями:

  • Идентификаторы, являющиеся ключевыми словами, нельзя использовать для других целей.
  • Единственное место, где их можно использовать не как ключевые слова, — это attribute-token (например, [[private]] — допустимый атрибут).
(начиная с C++11)
  • Идентификаторы, являющиеся альтернативными представлениями некоторых операторов и знаков пунктуации, нельзя использовать для других целей.
  • Идентификаторы со специальным значением (final, import, module(начиная с C++20) и override) используются явно в определённом контексте, а не являются обычными идентификаторами.
    • Если не указано иное, любая неоднозначность относительно того, имеет ли данный идентификатор специальное значение, разрешается в пользу трактовки токена как обычного идентификатора.
(начиная с C++11)
  • Идентификаторы, появляющиеся в виде токена или токена препроцессора (то есть не внутри user-defined-string-literal, например operator ""id)(начиная с C++11) в одной из следующих форм, зарезервированы:
    • в глобальном пространстве имён — идентификаторы, начинающиеся с символа подчёркивания
    • идентификаторы, содержащие два символа подчёркивания подряд или начинающиеся с символа подчёркивания, за которым следует прописная буква, за исключением следующих идентификаторов:
  • предопределённые макросы (включая макросы проверки поддержки языковых возможностей)(начиная с C++20)
  • std::_Exit
  • __func__
(начиная с C++11)
  • следующие макросы, определённые в стандартной библиотеке:
    • макросы библиотеки ввода-вывода в стиле C _PRINTF_NAN_LEN_MAX, (начиная с C++26)_IOFBF, _IOLBF и _IONBF
  • макросы совместимости с C __alignas_is_defined и __alignof_is_defined (определённые в <stdalign.h>)
  • макрос совместимости с C __bool_true_false_are_defined (определённый в <stdbool.h>)
(начиная с 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&
    };
}
  • Если обозначенная сущность является объектом параметра шаблона для параметра шаблона типа T, тип выражения — constT.
(начиная с C++20)
(начиная с C++11)

Неквалифицированные идентификаторы

Помимо надлежащим образом объявленных идентификаторов, в выражениях в той же роли можно использовать следующее:

  • имя перегруженного оператора в функциональной записи, например operator+ или operator new;
  • имя пользовательской функции преобразования, например operator bool;
  • имя пользовательского оператора литерала, например operator "" _km;
(начиная с C++11)
  • имя шаблона с последующим списком аргументов, например MyTemplate<int>;
  • символ ~, за которым следует имя класса, например ~MyClass;
  • символ ~, за которым следует спецификатор decltype, например ~decltype(str).
(начиная с C++11)
  • символ ~, за которым следует спецификатор индексирования набора, например ~pack...[0].
(начиная с C++26)

Вместе с идентификаторами они называются выражениями с неквалифицированными идентификаторами.

Квалифицированные идентификаторы

Выражение с квалифицированным идентификатором — это выражение с неквалифицированным идентификатором, перед которым стоит оператор разрешения области видимости :: и которому может предшествовать последовательность из любого количества следующих элементов, разделённых операторами разрешения области видимости:

  • имя пространства имён;
  • имя класса;
  • имя перечисления;
  • спецификатор decltype, обозначающий тип класса или перечисления.
(начиная с 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)
  • имя пользовательского оператора литерала (operator ""_km)
(начиная с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API