< cpp‎ | language
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
range-for (C++11)
Jump statements
Function declaration
Lambda function declaration
inline specifier
Dynamic exception specifications (until C++20)
noexcept specifier (C++11)
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Alternative representations
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Attributes (C++11)
typedef declaration
Type alias declaration (C++11)
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Class-specific function properties
explicit (C++11)
Special member functions

An identifier is an arbitrarily long sequence of digits, underscores, lowercase and uppercase Latin letters, and most Unicode characters. A valid identifier must begin with a non-digit character (Latin letter, underscore, or Unicode character of class XID_Start) and may contain non-digit characters, digits, and Unicode characters of class XID_Continue in non-initial positions. Identifiers are case-sensitive (lowercase and uppercase letters are distinct), and every character is significant. Every identifier must conform Normalization Form C.

Note: Support of Unicode identifiers is limited in most implementations, e.g. gcc (until 10).


[edit] In declarations

An identifier can be used to name objects, references, functions, enumerators, types, class members, namespaces, templates, template specializations, parameter packs, goto labels, and other entities, with the following exceptions:

  • the identifiers that are keywords cannot be used for other purposes;
    • The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11)
  • the identifiers that are alternative representations for certain operators and punctuators cannot be used for other purposes;
  • the identifiers with special meaning (final, import, module (since C++20) and override) are used explicitly in a certain context rather than being regular identifiers;
    • Unless otherwise specified, any ambiguity as to whether a given identifier has a special meaning is resolved to interpret the token as a regular identifier.
(since C++11)
  • the identifiers with a double underscore anywhere are reserved;
  • the identifiers that begin with an underscore followed by an uppercase letter are reserved;
  • the identifiers that begin with an underscore are reserved in the global namespace.

"Reserved" here means that the standard library headers #define or declare such identifiers for their internal needs, the compiler may predefine non-standard identifiers of that kind, and that name mangling algorithm may assume that some of these identifiers are not in use. If the programmer uses such identifiers, the behavior is undefined.

In addition, it's undefined behavior to #define or #undef certain names in a translation unit, see reserved macro names for more details.

[edit] Zombie identifiers

As of C++14, some identifiers are removed from the C++ standard library. They are listed in the list of zombie names.

However, these identifiers are still reserved for previous standardization in a certain context. Removed member function names may not be used as a name for function-like macros, and other removed member names may not be used as a name for object-like macros in portable code.

[edit] In expressions

An identifier that names a variable, a function, specialization of a concept, (since C++20) or an enumerator can be used as an expression. The result of an expression consisting of just the identifier is the entity named by the identifier. The value category of the expression is lvalue if the identifier names a function, a variable, a template parameter object (since C++20), or a data member, and prvalue otherwise (e.g. an enumerator is a prvalue expression, a specialization of a concept is a bool prvalue (since C++20)). The type of the expression is determined as follows:

  • If the entity named by the (unqualified) identifier is a local entity, and would result in an intervening lambda expression capturing it by copy if it were named outside of an unevaluated operand in the declarative region in which the identifier appears, then the type of the expression is the type of a class member access expression naming the non-static data member that would be declared for such a capture in the closure object of the innermost such intervening lambda expression.
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&
(since C++11)
  • If the entity named is a template parameter object for a template parameter of type T, the type of the expression is const T.
(since C++20)
  • Otherwise, the type of the expression is the same as the type of the entity named.

Within the body of a non-static member function, each identifier that names a non-static member is implicitly transformed to a class member access expression this->member.

[edit] Unqualified identifiers

Besides suitably declared identifiers, the following can be used in expressions in the same role:

Together with identifiers they are known as unqualified id-expressions.

[edit] Qualified identifiers

A qualified id-expression is an unqualified id-expression prepended by a scope resolution operator ::, and optionally, a sequence of enumeration, (since C++11)class or namespace names or decltype expressions (since C++11) separated by scope resolution operators. For example, the expression std::string::npos is an expression that names the static member npos in the class string in namespace std. The expression ::tolower names the function tolower in the global namespace. The expression ::std::cout names the global variable cout in namespace std, which is a top-level namespace. The expression boost::signals2::connection names the type connection declared in namespace signals2, which is declared in namespace boost.

The keyword template may appear in qualified identifiers as necessary to disambiguate dependent template names.

See qualified lookup for the details of the name lookup for qualified identifiers.

[edit] Names

A name is the use of one of the following to refer to an entity:

  • an identifier;
  • an overloaded operator name in function notation (operator+, operator new);
  • a user-defined conversion function name (operator bool);
  • a user-defined literal operator name (operator "" _km);
  • a template name followed by its argument list (MyTemplate<int>).

Every name is introduced into the program by a declaration. A name used in more than one translation unit may refer to the same or different entities, depending on linkage.

When the compiler encounters an unknown name in a program, it associates it with the declaration that introduced the name by means of name lookup, except for the dependent names in template declarations and definitions (for those names, the compiler determines whether they name a type, a template, or some other entity, which may require explicit disambiguation).

[edit] See also

C documentation for Identifiers