Namespaces
Variants

Declarations

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Declarations are how names are introduced (or re-introduced) into the C++ program. Not all declarations actually declare anything, and each kind of entity is declared differently. Definitions are declarations that are sufficient to use the entity identified by the name.

A declaration is one of the following:

  • Attribute declaration ( attr ; )
(since C++11)
  • Empty declaration ( ; )
  • A function declaration without a decl-specifier-seq :
attr  (optional) declarator ;
attr - (since C++11) sequence of any number of attributes
declarator - a function declarator
This declaration must declare a constructor, destructor, or user-defined type conversion function . It can only be used as part of a template declaration , explicit specialization , or explicit instantiation.
  • block-declaration (a declaration that can appear inside a block ), which, in turn, can be one of the following:
(since C++11)
(since C++20)
(since C++11)
  • simple declaration

Contents

Simple declaration

A simple declaration is a statement that introduces, creates, and optionally initializes one or several identifiers, typically variables.

decl-specifier-seq init-declarator-list  (optional) ; (1)
attr decl-specifier-seq init-declarator-list ; (2) (since C++11)
decl-specifier-seq - sequence of specifiers
init-declarator-list - comma-separated list of init-declarator s (see below)
attr - sequence of any number of attributes


init-declarator-list can only be omitted when declaring a named class or a named enumeration.

A structured binding declaration is also a simple declaration.

(since C++17)


The syntax of init-declarator is defined as follows:

declarator initializer (1)
declarator requires-clause  (optional) contract-specs  (optional) (2)
1) A declarator with an initializer.
2) A declarator without an initializer.
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 can only appear if declarator declares a templated function .

(since C++20)

contract-specs can only appear if declarator declares a function or function template.

(since C++26)

Specifiers

Declaration specifiers ( decl-specifier-seq ) is a sequence of the following whitespace-separated specifiers, in any order:

  • the inline specifier is also allowed on variable declarations.
(since C++17)
  • the friend specifier, allowed in class and function declarations.
  • the constexpr specifier, only allowed in variable definitions, function and function template declarations, and the declaration of static data members of literal type.
(since C++11)
  • the consteval specifier, only allowed in function and function template declarations.
  • the constinit specifier, only allowed in declaration of a variable with static or thread storage duration. At most one of the constexpr , consteval , and constinit specifiers is allowed to appear in a decl-specifier-seq .
(since C++20)
  • storage class specifier ( register , (until C++17) static , thread_local , (since C++11) extern , mutable ). Only one storage class specifier is allowed , except that thread_local may appear together with extern or static (since C++11) .
  • Type specifiers ( type-specifier-seq ), a sequence of specifiers that names a type. The type of every entity introduced by the declaration is this type, optionally modified by the declarator (see below). This sequence of specifiers is also used by type-id . Only the following specifiers are part of type-specifier-seq , in any order:
(since C++11)
(since C++26)
(since C++17)
only one type specifier is allowed in a decl-specifier-seq, with the following exceptions:
  • const can be combined with any type specifier except itself.
  • volatile can be combined with any type specifier except itself.
  • signed or unsigned can be combined with char , long , short , or int .
  • short or long can be combined with int .
  • long can be combined with double .
  • long can be combined with long .
(since C++11)

Attributes may appear in decl-specifier-seq , in which case they apply to the type determined by the preceding specifiers.

Repetitions of any specifier in a decl-specifier-seq , such as const static const , or virtual inline virtual are errors , except that long is allowed to appear twice (since C++11) .

Declarators

Each init-declarator in an init-declarator-list S D1, D2, D3 ; is processed as if it were a standalone declaration with the same specifiers: S D1 ; S D2 ; S D3 ; .

Each declarator introduces exactly one object, reference, function, or (for typedef declarations) type alias, whose type is provided by decl-specifier-seq and optionally modified by operators such as & (reference to) or [ ] (array of) or ( ) (function returning) in the declarator. These operators can be applied recursively, as shown below.

A declarator is one of the following:

unqualified-id attr  (optional) (1)
qualified-id attr  (optional) (2)
... identifier attr  (optional) (3) (since C++11)
* attr  (optional) cv  (optional) declarator (4)
nested-name-specifier * attr  (optional) cv  (optional) declarator (5)
& attr  (optional) declarator (6)
&& attr  (optional) declarator (7) (since C++11)
noptr-declarator [ constant-expression  (optional) ] attr  (optional) (8)
noptr-declarator ( parameter-list ) cv  (optional) ref   (optional) except  (optional) attr  (optional) (9)
( declarator ) (10)
1) The name that is declared.
2) A declarator that uses a qualified identifier ( qualified-id ) defines or redeclares a previously declared namespace member or class member .
4) Pointer declarator : the declaration S * D ; declares D as a pointer to the type determined by decl-specifier-seq S .
5) Pointer to member declaration : the declaration S C :: * D ; declares D as a pointer to member of C of type determined by decl-specifier-seq S . nested-name-specifier is a sequence of names and scope resolution operators ::
6) Lvalue reference declarator : the declaration S & D ; declares D as an lvalue reference to the type determined by decl-specifier-seq S .
7) Rvalue reference declarator : the declaration S && D ; declares D as an rvalue reference to the type determined by decl-specifier-seq S .
8) Array declarator . noptr-declarator any valid declarator, but if it begins with *, &, or &&, it has to be surrounded by parentheses.
9) Function declarator . noptr-declarator any valid declarator, but if it begins with *, &, or &&, it has to be surrounded by parentheses. It may end with the optional trailing return type. (since C++11)
10) Parenthesized declarator.

In all cases, attr is an optional sequence of attributes . When appearing immediately after the identifier, it applies to the object being declared.

(since C++11)

cv is a sequence of const and volatile qualifiers, where either qualifier may appear at most once in the sequence.

Notes

When a block-declaration appears inside a block , and an identifier introduced by a declaration was previously declared in an outer block, the outer declaration is hidden for the remainder of the block.

If a declaration introduces a variable with automatic storage duration, it is initialized when its declaration statement is executed. All automatic variables declared in a block are destroyed on exit from the block (regardless how the block is exited: via exception , goto , or by reaching its end), in order opposite to their order of initialization.

Example

Note: this example demonstrates how some complex declarations are parsed in terms of the language grammar. Other popular mnemonics are: the spiral rule , reading inside-out , and declaration mirrors use . There is also an automated parser at 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)>);
}

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 482 C++98 the declarators of redeclarations could not be qualified qualified declarators allowed
CWG 569 C++98 a single standalone semicolon was not a valid declaration it is an empty declaration,
which has no effect
CWG 1830 C++98 repetition of a function specifier in a decl-specifier-seq was allowed repetition is forbidden

See also

C documentation for Declarations