12 KiB
[dcl.meaning.general]
9 Declarations [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.
If the unqualified-id occurring in a declarator-id is a template-id, the declarator shall appear in the declaration of atemplate-declaration ([temp.decls]),explicit-specialization ([temp.expl.spec]), orexplicit-instantiation ([temp.explicit]).
[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: + (2.2.1.1) if the unqualified-id in E is a template-id, all function declarations are discarded;
-
[(2.2.1.2)](#2.2.1.2)
-
-
otherwise, if the declarator corresponds ([basic.scope.scope]) to any declaration found of a non-template function, all function template declarations are discarded;
+
[(2.2.1.3)](#2.2.1.3)
each remaining function template is replaced with the specialization chosen by deduction from the friend declaration ([temp.deduct.decl]) or discarded if deduction fails.
-
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 void f(T); // #1template void g(T) {}}namespace P {template void f(T*); // #2, more specialized than #1template int g; }using P::f,P::g;}template<> void N::f(int*) {} // OK, #2 is not nominabletemplate 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() { /* ... / } // OKvoid V::g() { / ... / } // error: g() is not yet a member of Vnamespace 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 declaredextern void q(); // q is a member of namespace Xextern 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 qvoid X::r() { / ... */ } // error: r cannot be declared by qualified-id â end example]
Astatic,thread_local,extern,mutable,friend,inline,virtual,constexpr,consteval,constinit, ortypedef 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 formT D whereT is of the form attribute-specifier-seqoptdecl-specifier-seq andD is a declarator.
Following is a recursive procedure for determining the type specified for the containeddeclarator-id by such a declaration.
First, thedecl-specifier-seq determines a type.
In a declarationT D thedecl-specifier-seqT determines the typeT.
[Example 4:
In the declarationint unsigned i; the type specifiersintunsigned determine the type âunsigned intâ ([dcl.type.simple]).
â end example]
In a declarationattribute-specifier-seqoptTD whereD is an unadorned declarator-id, the type of the declared entity is âTâ.
In a declarationTD whereD has the form
( D1 )
the type of the containeddeclarator-id is the same as that of the containeddeclarator-id in the declarationT D1
Parentheses do not alter the type of the embeddeddeclarator-id, but they can alter the binding of complex declarators.