9 Declarations [dcl.dcl]

9.3 Declarators [dcl.decl]

9.3.4 Meaning of declarators [dcl.meaning]

9.3.4.1 General [dcl.meaning.general]

A declarator contains exactly one declarator-id; it names the entity that is declared.
[Note 1: 
An unqualified-id that is not an identifier is used to declare certain functions ([class.conv.fct], [class.dtor], [over.oper], [over.literal]).
— end note]
The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared.
If the declaration is a friend declaration:
  • The declarator does not bind a name.
  • If the id-expression E in the declarator-id of the declarator is a qualified-id or a template-id:
    • If the friend declaration is not a template declaration, then in the lookup for the terminal name of E:
    • The declarator shall correspond to one or more declarations found by the lookup; they shall all have the same target scope, and the target scope of the declarator is that scope.
  • Otherwise, the terminal name of E is not looked up.
    The declaration's target scope is the innermost enclosing namespace scope; if the declaration is contained by a block scope, the declaration shall correspond to a reachable ([module.reach]) declaration that inhabits the innermost block scope.
Otherwise:
  • If the id-expression in the declarator-id of the declarator is a qualified-id Q, let S be its lookup context ([basic.lookup.qual]); the declaration shall inhabit a namespace scope.
  • Otherwise, let S be the entity associated with the scope inhabited by the declarator.
  • If the declarator declares an explicit instantiation or a partial or explicit specialization, the declarator does not bind a name.
    If it declares a class member, the terminal name of the declarator-id is not looked up; otherwise, only those lookup results that are nominable in S are considered when identifying any function template specialization being declared ([temp.deduct.decl]).
    [Example 1: namespace N { inline namespace O { template<class T> void f(T); // #1 template<class T> void g(T) {} } namespace P { template<class T> void f(T*); // #2, more specialized than #1 template<class> int g; } using P::f,P::g; } template<> void N::f(int*) {} // OK, #2 is not nominable template void N::g(int); // error: lookup is ambiguous — end example]
  • Otherwise, the terminal name of the declarator-id is not looked up.
    If it is a qualified name, the declarator shall correspond to one or more declarations nominable in S; all the declarations shall have the same target scope and the target scope of the declarator is that scope.
    [Example 2: namespace Q { namespace V { void f(); } void V::f() { /* ... */ } // OK void V::g() { /* ... */ } // error: g() is not yet a member of V namespace V { void g(); } } namespace R { void Q::V::g() { /* ... */ } // error: R doesn't enclose Q } — end example]
  • If the declaration inhabits a block scope S and declares a function ([dcl.fct]) or uses the extern specifier, the declaration shall not be attached to a named module ([module.unit]); its target scope is the innermost enclosing namespace scope, but the name is bound in S.
    [Example 3: namespace X { void p() { q(); // error: q not yet declared extern void q(); // q is a member of namespace X extern void r(); // r is a member of namespace X } void middle() { q(); // error: q not found } void q() { /* ... */ } // definition of X​::​q } void q() { /* ... */ } // some other, unrelated q void X::r() { /* ... */ } // error: r cannot be declared by qualified-id — end example]
A static, thread_local, extern, mutable, friend, inline, virtual, constexpr, consteval, constinit, or typedef specifier or an explicit-specifier applies directly to each declarator-id in a declaration; the type specified for each declarator-id depends on both the decl-specifier-seq and its declarator.
Thus, (for each declarator) a declaration has the form T D where T is of the form attribute-specifier-seq decl-specifier-seq and D is a declarator.
Following is a recursive procedure for determining the type specified for the contained declarator-id by such a declaration.
First, the decl-specifier-seq determines a type.
In a declaration T D the decl-specifier-seq T determines the type T.
[Example 4: 
In the declaration int unsigned i; the type specifiers int unsigned determine the type “unsigned int” ([dcl.type.simple]).
— end example]
In a declaration attribute-specifier-seq T D where D is an unadorned declarator-id, the type of the declared entity is “T.
In a declaration T D where D has the form
( D1 )
the type of the contained declarator-id is the same as that of the contained declarator-id in the declaration T D1
Parentheses do not alter the type of the embedded declarator-id, but they can alter the binding of complex declarators.