[dcl.decl] (original) (raw)

9.3.1 General [dcl.decl.general]

A declarator declares a single variable, function, or type, within a declaration.

Theinit-declarator-listappearing in a simple-declarationis a comma-separated sequence of declarators, each of which can have an initializer.

In all contexts, a declarator is interpreted as given below.

Where an abstract-declarator can be used (or omitted) in place of a declarator ([dcl.fct], [except.pre]), it is as if a unique identifier were included in the appropriate place ([dcl.name]).

The preceding specifiers indicate the type, storage duration, linkage, or other properties of the entity or entities being declared.

Each declarator specifies one entity and (optionally) names it and/or modifies the type of the specifiers with operators such as* (pointer to) and () (function returning).

[Note 1:

An init-declarator can also specify an initializer ([dcl.init]).

— _end note_]

Each init-declarator or member-declaratorin a declaration is analyzed separately as if it were in a declaration by itself.

[Note 2:

A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator.

That is,T D1, D2, ... Dn;is usually equivalent toT D1; T D2; ... T Dn;where T is a decl-specifier-seqand each Di is an init-declarator or member-declarator.

One exception is when a name introduced by one of thedeclarators hides a type name used by thedecl-specifiers, so that when the samedecl-specifiers are used in a subsequent declaration, they do not have the same meaning, as instruct S { }; S S, T; which is not equivalent tostruct S { }; S S; S T;

Another exception is when T is auto ([dcl.spec.auto]), for example:auto i = 1, j = 2.0; as opposed toauto i = 1; auto j = 2.0;

— _end note_]

[Example 1: void f1(int a) requires true; template<typename T> auto f2(T a) -> bool requires true; template<typename T> auto f3(T a) requires true -> bool; void (*pf)() requires true; void g(int (*)() requires true); auto* p = new void(*)(char) requires true; — _end example_]

Declarators have the syntax

cv-qualifier:
const
volatile

9.3.2 Type names [dcl.name]

To specify type conversions explicitly,and as an argument ofsizeof,alignof,new, ortypeid, the name of a type shall be specified.

This can be done with atype-id or new-type-id ([expr.new]), which is syntactically a declaration for a variable or function of that type that omits the name of the entity.

It is possible to identify uniquely the location in theabstract-declaratorwhere the identifier would appear if the construction were a declarator in a declaration.

The named type is then the same as the type of the hypothetical identifier.

[Example 1:

int int * int *[3] int (*)[3] int *() int (*)(double) name respectively the types “int”, “pointer toint”, “array of 3 pointers toint”, “pointer to array of 3int”, “function of (no parameters) returning pointer toint”, and “pointer to a function of (double) returningint”.

— _end example_]

9.3.3 Ambiguity resolution [dcl.ambig.res]

The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration.

In that context, the choice is between an object declaration with a function-style cast as the initializer and a declaration involving a function declarator with a redundant set of parentheses around a parameter name.

Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct, such as the potential parameter declaration, that could possibly be a declaration to be a declaration.

However, a construct that can syntactically be a declarationwhose outermost declaratorwould match the grammar of a declaratorwith a trailing-return-typeis a declaration only if it starts with auto.

[Note 1:

A declaration can be explicitly disambiguated by adding parentheses around the argument.

The ambiguity can be avoided by use of copy-initialization or list-initialization syntax, or by use of a non-function-style cast.

— _end note_]

[Example 1: struct S { S(int);};typedef struct BB { int C[2]; } *B, C;void foo(double a) { S v(int(a)); S w(int()); S x((int(a))); S y((int)a); S z = int(a); S a(B()->C); S b(auto()->C); } — _end example_]

An ambiguity can arise from the similarity between a function-style cast and atype-id.

The resolution is that any construct that could possibly be atype-idin its syntactic context shall be considered atype-id.

However, a construct that can syntactically be a type-idwhose outermost abstract-declaratorwould match the grammar of an abstract-declaratorwith a trailing-return-typeis considered a type-id only if it starts with auto.

[Example 2: template <class T> struct X {};template <int N> struct Y {}; X<int()> a; X<int(1)> b; Y<int()> c; Y<int(1)> d; void foo(signed char a) { sizeof(int()); sizeof(int(a)); sizeof(int(unsigned(a))); (int())+1; (int(a))+1; (int(unsigned(a)))+1; } typedef struct BB { int C[2]; } *B, C;void g() { sizeof(B()->C[1]); sizeof(auto()->C[1]); } — _end example_]

Another ambiguity arises in aparameter-declaration-clause when atype-nameis nested in parentheses.

In this case, the choice is between the declaration of a parameter of type pointer to function and the declaration of a parameter with redundant parentheses around thedeclarator-id.

[Example 3: class C { };void f(int(C)) { } int g(C);void foo() { f(1); f(g); }

For another example,class C { };void h(int *(C[10]));

— _end example_]

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 declaration is a friend declaration:

Otherwise:

Astatic,thread_local,extern,mutable,friend,inline,virtual,constexpr,consteval,constinit, ortypedefspecifier or an explicit-specifierapplies directly to each declarator-idin a declaration; the type specified for each declarator-id depends on both the decl-specifier-seq and its declarator.

Following is a recursive procedure for determining the type specified for the containeddeclarator-idby such a declaration.

[Example 4:

In the declarationint unsigned i;the type specifiersint unsigneddetermine the type “unsigned int” ([dcl.type.simple]).

— _end example_]

In a declarationT DwhereDhas the form

( D1 )

the type of the containeddeclarator-idis the same as that of the containeddeclarator-idin the declarationT D1

Parentheses do not alter the type of the embeddeddeclarator-id, but they can alter the binding of complex declarators.

9.3.4.2 Pointers [dcl.ptr]

In a declarationT DwhereDhas the form

and the type of the contained declarator-id in the declarationT D1is “derived-declarator-type-list T”, the type of the declarator-id inDis “derived-declarator-type-list cv-qualifier-seq pointer toT”.

Thecv-qualifier_s_apply to the pointer and not to the object pointed to.

[Example 1:

The declarationsconst int ci = 10, *pc = &ci, *const cpc = pc, **ppc;int i, *p, *const cp = &i;declareci, a constant integer;pc, a pointer to a constant integer;cpc, a constant pointer to a constant integer;ppc, a pointer to a pointer to a constant integer;i, an integer;p, a pointer to integer; andcp, a constant pointer to integer.

The value ofci,cpc, andcpcannot be changed after initialization.

The value ofpccan be changed, and so can the object pointed to bycp.

Examples of some correct operations arei = ci;*cp = ci; pc++; pc = cpc; pc = p; ppc = &pc;

Examples of ill-formed operations areci = 1; ci++; *pc = 2; cp = &ci; cpc++; p = pc; ppc = &p;

Each is unacceptable because it would either change the value of an object declaredconstor allow it to be changed through a cv-unqualified pointer later, for example:*ppc = &ci; *p = 5;

— _end example_]

[Note 1:

Forming a pointer to reference type is ill-formed; see [dcl.ref].

Forming a function pointer type is ill-formed if the function type hascv-qualifiers or a ref-qualifier; see [dcl.fct].

Since the address of a bit-field ([class.bit]) cannot be taken, a pointer can never point to a bit-field.

— _end note_]

9.3.4.3 References [dcl.ref]

In a declarationT DwhereDhas either of the forms

and the type of the contained declarator-id in the declarationT D1is “derived-declarator-type-list T”, the type of the declarator-id inDis “derived-declarator-type-list reference toT”.

[Example 1: typedef int& A;const A aref = 3;

The type ofarefis “lvalue reference to int”, not “lvalue reference to const int”.

— _end example_]

[Note 1:

A reference can be thought of as a name of an object.

— _end note_]

Forming the type “reference to cv void” is ill-formed.

A reference type that is declared using & is called anlvalue reference, and a reference type that is declared using && is called anrvalue reference.

Lvalue references and rvalue references are distinct types.

Except where explicitly noted, they are semantically equivalent and commonly referred to as references.

[Example 2:

void f(double& a) { a += 3.14; } double d = 0; f(d);declaresato be a reference parameter offso the callf(d)will add3.14tod.

int v[20];int& g(int i) { return v[i]; }g(3) = 7;declares the functiong()to return a reference to an integer sog(3)=7will assign7to the fourth element of the arrayv.

For another example,struct link { link* next;}; link* first;void h(link*& p) { p->next = first; first = p; p = 0;} void k() { link* q = new link; h(q);} declarespto be a reference to a pointer tolinksoh(q)will leaveqwith the value zero.

— _end example_]

It is unspecified whether or not a reference requires storage ([basic.stc]).

There shall be no references to references, no arrays of references, and no pointers to references.

The declaration of a reference shall contain aninitializer ([dcl.init.ref]) except when the declaration contains an explicitexternspecifier ([dcl.stc]), is a class member ([class.mem]) declaration within a class definition, or is the declaration of a parameter or a return type ([dcl.fct]); see [basic.def].

Attempting to bind a reference to a function where the converted initializer is a glvalue whose type is not call-compatible ([expr.call]) with the type of the function's definition results in undefined behavior.

Attempting to bind a reference to an object where the converted initializer is a glvalue through which the object is not type-accessible ([basic.lval]) results in undefined behavior.

[Note 2:

The object designated by such a glvalue can be outside its lifetime ([basic.life]).

Because a null pointer value or a pointer past the end of an object does not point to an object, a reference in a well-defined program cannot refer to such things; see [expr.unary.op].

As described in [class.bit], a reference cannot be bound directly to a bit-field.

— _end note_]

The behavior of an evaluation of a reference ([expr.prim.id], [expr.ref]) that does not happen after ([intro.races]) the initialization of the reference is undefined.

[Example 3: int &f(int&);int &g();extern int &ir3;int *ip = 0;int &ir1 = *ip; int &ir2 = f(ir3); int &ir3 = g();int &ir4 = f(ir4); char x alignas(int);int &ir5 = *reinterpret_cast<int *>(&x); — _end example_]

If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier ([dcl.type.decltype]) denotes a type TR that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR.

[Note 3:

This rule is known as reference collapsing.

— _end note_]

[Example 4: int i;typedef int& LRI;typedef int&& RRI; LRI& r1 = i; const LRI& r2 = i; const LRI&& r3 = i; RRI& r4 = i; RRI&& r5 = 5; decltype(r2)& r6 = i; decltype(r2)&& r7 = i; — _end example_]

[Note 4:

Forming a reference to function type is ill-formed if the function type has cv-qualifiers or a ref-qualifier; see [dcl.fct].

— _end note_]

9.3.4.4 Pointers to members [dcl.mptr]

In a declarationT DwhereDhas the form

and thenested-name-specifierdenotes a class, and the type of the contained declarator-id in the declarationT D1is “derived-declarator-type-list T”, the type of the declarator-id inDis “derived-declarator-type-list cv-qualifier-seq pointer to member of classnested-name-specifier of typeT”.

[Example 1:

struct X { void f(int);int a;};struct Y;int X::* pmi = &X::a;void (X::* pmf)(int) = &X::f;double X::* pmd;char Y::* pmc;declarespmi,pmf,pmdandpmcto be a pointer to a member ofXof typeint, a pointer to a member ofXof typevoid(int), a pointer to a member ofXof typedoubleand a pointer to a member ofYof typecharrespectively.

The declaration ofpmdis well-formed even thoughXhas no members of typedouble.

Similarly, the declaration ofpmcis well-formed even thoughYis an incomplete type.

pmiandpmfcan be used like this:X obj; obj.*pmi = 7; (obj.*pmf)(7);

— _end example_]

A pointer to member shall not point to a static member of a class ([class.static]), a member with reference type, or “cv void”.

[Note 1:

The type “pointer to member” is distinct from the type “pointer”, that is, a pointer to member is declared only by the pointer-to-member declarator syntax, and never by the pointer declarator syntax.

There is no “reference-to-member” type in C++.

— _end note_]

9.3.4.5 Arrays [dcl.array]

In a declaration T D where D has the form

and the type of the contained declarator-idin the declaration T D1is “derived-declarator-type-list T”, the type of the declarator-id in D is “derived-declarator-type-list array of N T”.

Its value N specifies the array bound, i.e., the number of elements in the array;N shall be greater than zero.

In a declaration T D where D has the form

and the type of the contained declarator-idin the declaration T D1is “derived-declarator-type-list T”, the type of the declarator-id in D is “derived-declarator-type-list array of unknown bound of T”, except as specified below.

A type of the form “array of N U” or “array of unknown bound of U” is an array type.

U is called the array element type; this type shall not be a reference type, a function type, an array of unknown bound, orcv void.

[Note 1:

An array can be constructed from one of the fundamental types (except void), from a pointer, from a pointer to member, from a class, from an enumeration type, or from an array of known bound.

— _end note_]

[Example 1:

float fa[17], *afp[17];declares an array of float numbers and an array of pointers to float numbers.

— _end example_]

Any type of the form “cv-qualifier-seq array of N U” is adjusted to “array of N cv-qualifier-seq U”, and similarly for “array of unknown bound of U”.

[Example 2: typedef int A[5], AA[2][3];typedef const A CA; typedef const AA CAA; — _end example_]

An object of type “array of N U” consists of a contiguously allocated non-empty set of N subobjects of type U, known as the elements of the array, and numbered 0 to N-1.

In addition to declarations in which an incomplete object type is allowed, an array bound may be omitted in some cases in the declaration of a function parameter ([dcl.fct]).

An array bound may also be omitted when an object (but not a non-static data member) of array type is initialized and the declarator is followed by an initializer ([dcl.init], [class.mem], [expr.type.conv], [expr.new]).

In these cases, the array bound is calculated from the number of initial elements (say, N) supplied ([dcl.init.aggr]), and the type of the array is “array of N U”.

Furthermore, if there is a reachable declaration of the entity that inhabits the same scope in which the bound was specified, an omitted array bound is taken to be the same as in that earlier declaration, and similarly for the definition of a static data member of a class.

[Example 3: extern int x[10];struct S { static int y[10];};int x[]; int S::y[]; void f() { extern int x[];int i = sizeof(x); } — _end example_]

[Note 3:

When several “array of” specifications are adjacent, a multidimensional array type is created; only the first of the constant expressions that specify the bounds of the arrays can be omitted.

[Example 4:

int x3d[3][5][7];declares an array of three elements, each of which is an array of five elements, each of which is an array of seven integers.

The overall array can be viewed as a three-dimensional array of integers, with rank 3 ×5 ×7.

Any of the expressionsx3d,x3d[i],x3d[i][j],x3d[i][j][k]can reasonably appear in an expression.

The expressionx3d[i]is equivalent to*(x3d + i); in that expression,x3dis subject to the array-to-pointer conversion ([conv.array]) and is first converted to a pointer to a 2-dimensional array with rank5 ×7that points to the first element of x3d.

Then i is added, which on typical implementations involves multiplyingi by the length of the object to which the pointer points, which is sizeof(int)×5 ×7.

The result of the addition and indirection is an lvalue denoting the array element ofx3d(an array of five arrays of seven integers).

If there is another subscript, the same argument applies again, sox3d[i][j] is an lvalue denoting the array element of the array element ofx3d(an array of seven integers), andx3d[i][j][k] is an lvalue denoting the array element of the array element of the array element ofx3d(an integer).

— _end example_]

The first subscript in the declaration helps determine the amount of storage consumed by an array but plays no other part in subscript calculations.

— _end note_]

[Note 4:

Conversions affecting expressions of array type are described in [conv.array].

— _end note_]

[Note 5:

The subscript operator can be overloaded for a class ([over.sub]).

For the operator's built-in meaning, see [expr.sub].

— _end note_]

9.3.4.6 Functions [dcl.fct]

In a declarationT DwhereT may be empty andDhas the form

a derived-declarator-type-list is determined as follows:

The declared return type U of the function type is determined as follows:

The type of thedeclarator-idinDis “derived-declarator-type-list noexceptfunction of parameter-type-listcv-qualifier-seq ref-qualifierreturning U”, where

Such a type is a function type.75

Theparameter-declaration-clausedetermines the arguments that can be specified, and their processing, when the function is called.

[Note 1:

Theparameter-declaration-clauseis used to convert the arguments specified on the function call; see [expr.call].

— _end note_]

If theparameter-declaration-clauseis empty, the function takes no arguments.

A parameter list consisting of a single unnamed non-object parameter of non-dependent type void is equivalent to an empty parameter list.

Except for this special case, a parameter shall not have type cv void.

If theparameter-declaration-clause terminates with an ellipsis or a function parameter pack ([temp.variadic]), the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument and are not function parameter packs.

Where syntactically correct and where “...” is not part of an abstract-declarator, “...” is synonymous with “, ...”.

[Example 1:

The declarationint printf(const char*, ...);declares a function that can be called with varying numbers and types of arguments.

printf("hello world"); printf("a=%d b=%d", a, b);

However, the first argument must be of a type that can be converted to aconst char*.

— _end example_]

The type of a function is determined using the following rules.

The type of each parameter (including function parameter packs) is determined from its own parameter-declaration ([dcl.decl]).

After determining the type of each parameter, any parameterof type “array of T” orof function type Tis adjusted to be “pointer to T”.

After producing the list of parameter types, any top-levelcv-qualifier_s_modifying a parameter type are deleted when forming the function type.

The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function'sparameter-type-list.

[Note 3:

This transformation does not affect the types of the parameters.

For example, int(*)(const int p, decltype(p)*) andint(*)(int, const int*) are identical types.

— _end note_]

[Example 2: void f(char*); void f(char[]) {} void f(const char*) {} void f(char *const) {} void g(char(*)[2]); void g(char[3][2]) {} void g(char[3][3]) {} void h(int x(const int)); void h(int (*)(int)) {} — _end example_]

An explicit-object-parameter-declaration is a parameter-declaration with a this specifier.

A member-declarator with an explicit-object-parameter-declaration shall not include a ref-qualifier or a cv-qualifier-seq and shall not be declared static or virtual.

[Example 3: struct C { void f(this C& self);template <typename Self> void g(this Self&& self, int);void h(this C) const; };void test(C c) { c.f(); c.g(42); std::move(c).g(42); } — _end example_]

A function parameter declared with an explicit-object-parameter-declaration is an explicit object parameter.

An explicit object parameter shall not be a function parameter pack ([temp.variadic]).

An explicit object member function is a non-static member function with an explicit object parameter.

An implicit object member function is a non-static member function without an explicit object parameter.

The object parameter of a non-static member function is either the explicit object parameter or the implicit object parameter ([over.match.funcs]).

A non-object parameter is a function parameter that is not the explicit object parameter.

The non-object-parameter-type-list of a member function is the parameter-type-list of that function with the explicit object parameter, if any, omitted.

[Note 4:

The non-object-parameter-type-list consists of the adjusted types of all the non-object parameters.

— _end note_]

[Example 4: typedef int FIC(int) const; FIC f; struct S { FIC f; }; FIC S::*pm = &S::f; — _end example_]

The effect of acv-qualifier-seqin a function declarator is not the same as adding cv-qualification on top of the function type.

In the latter case, the cv-qualifiers are ignored.

[Note 5:

A function type that has a cv-qualifier-seq is not a cv-qualified type; there are no cv-qualified function types.

— _end note_]

[Example 5: typedef void F();struct S { const F f; }; — _end example_]

The return type, the parameter-type-list, the ref-qualifier, the cv-qualifier-seq, and the exception specification, but not the default arguments ([dcl.fct.default]) or the trailing requires-clause ([dcl.decl]), are part of the function type.

[Note 6:

Function types are checked during the assignments and initializations of pointers to functions, references to functions, and pointers to member functions.

— _end note_]

[Example 6:

The declarationint fseek(FILE*, long, int);declares a function taking three arguments of the specified types, and returningint ([dcl.type]).

— _end example_]

[Note 7:

A single name can be used for several different functions in a single scope; this is function overloading ([over]).

— _end note_]

The return type shall be a non-array object type, a reference type, or cv void.

[Note 8:

An array of placeholder type is considered an array type.

— _end note_]

Types shall not be defined in return or parameter types.

A typedef of function type may be used to declare a function but shall not be used to define a function ([dcl.fct.def]).

[Example 7: typedef void F(); F fv; F fv { } void fv() { } — _end example_]

An identifier can optionally be provided as a parameter name; if present in a function definition ([dcl.fct.def]), it names a parameter.

[Note 9:

In particular, parameter names are also optional in function definitions and names used for a parameter in different declarations and the definition of a function need not be the same.

— _end note_]

[Example 8:

The declarationint i,*pi, f(),*fpi(int),(*pif)(const char*, const char*),(*fpif(int))(int);declares an integeri, a pointerpito an integer, a functionftaking no arguments and returning an integer, a functionfpitaking an integer argument and returning a pointer to an integer, a pointerpifto a function which takes two pointers to constant characters and returns an integer, a functionfpiftaking an integer argument and returning a pointer to a function that takes an integer argument and returns an integer.

It is especially useful to comparefpiandpif.

The binding of*fpi(int)is*(fpi(int)), so the declaration suggests, and the same construction in an expression requires, the calling of a functionfpi, and then using indirection through the (pointer) result to yield an integer.

In the declarator(*pif)(const char*, const char*), the extra parentheses are necessary to indicate that indirection through a pointer to a function yields a function, which is then called.

— _end example_]

[Note 10:

Typedefs and trailing-return-types are sometimes convenient when the return type of a function is complex.

For example, the functionfpifabove can be declaredtypedef int IFUNC(int); IFUNC* fpif(int);orauto fpif(int)->int(*)(int);

A trailing-return-type is most useful for a type that would be more complicated to specify before the declarator-id:template <class T, class U> auto add(T t, U u) -> decltype(t + u);rather thantemplate <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);

— _end note_]

A non-template function is a function that is not a function template specialization.

[Note 11:

A function template is not a function.

— _end note_]

An abbreviated function templateis a function declaration that has one or more generic parameter type placeholders ([dcl.spec.auto]).

An abbreviated function template is equivalent to a function template ([temp.fct]) whose template-parameter-list includes one invented type-parameterfor each generic parameter type placeholder of the function declaration, in order of appearance.

The invented type-parameter declares a template parameter pack if the corresponding parameter-declarationdeclares a function parameter pack.

If the placeholder contains decltype(auto), the program is ill-formed.

The adjusted function parameters of an abbreviated function template are derived from the parameter-declaration-clause by replacing each occurrence of a placeholder with the name of the corresponding invented type-parameter.

[Example 9: template<typename T> concept C1 = ;template<typename T> concept C2 = ;template<typename... Ts> concept C3 = ;void g1(const C1 auto*, C2 auto&);void g2(C1 auto&...);void g3(C3 auto...);void g4(C3 auto);

The declarations above are functionally equivalent (but not equivalent) to their respective declarations below:template<C1 T, C2 U> void g1(const T*, U&);template<C1... Ts> void g2(Ts&...);template<C3... Ts> void g3(Ts...);template<C3 T> void g4(T);

Abbreviated function templates can be specialized like all function templates.

template<> void g1<int>(const int*, const double&); — _end example_]

An abbreviated function template can have a template-head.

[Example 10: template<typename> concept C = ;template <typename T, C U> void g(T x, U y, C auto z);

This is functionally equivalent to each of the following two declarations.

template<typename T, C U, C W> void g(T x, U y, W z);template<typename T, typename U, typename W> requires C<U> && C<W> void g(T x, U y, W z); — _end example_]

A function declaration at block scope shall not declare an abbreviated function template.

A declarator-id or abstract-declaratorcontaining an ellipsis shall only be used in a parameter-declaration.

When it is part of aparameter-declaration-clause, the parameter-declaration declares a function parameter pack ([temp.variadic]).

A function parameter pack is a pack expansion ([temp.variadic]).

[Example 11: template<typename... T> void f(T (* ...t)(int, int));int add(int, int);float subtract(int, int);void g() { f(add, subtract);} — _end example_]

There is a syntactic ambiguity when an ellipsis occurs at the end of a parameter-declaration-clause without a preceding comma.

In this case, the ellipsis is parsed as part of theabstract-declarator if the type of the parameter either names a template parameter pack that has not been expanded or contains auto; otherwise, it is parsed as part of the parameter-declaration-clause.76

9.3.4.7 Default arguments [dcl.fct.default]

[Note 1:

Default arguments will be used in calls where trailing arguments are missing ([expr.call]).

— _end note_]

[Example 1:

The declarationvoid point(int = 3, int = 4);declares a function that can be called with zero, one, or two arguments of typeint.

It can be called in any of these ways:point(1,2); point(1); point();

The last two calls are equivalent topoint(1,4)andpoint(3,4), respectively.

— _end example_]

A default argument shall not be specified for a template parameter pack or a function parameter pack.

If it is specified in aparameter-declaration-clause, it shall not occur within adeclaratororabstract-declaratorof aparameter-declaration.77

For non-template functions, default arguments can be added in later declarations of a function that inhabit the same scope.

Declarations that inhabit different scopes have completely distinct sets of default arguments.

That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa.

In a given function declaration, each parameter subsequent to a parameter with a default argument shall have a default argument supplied in this or a previous declaration, unless the parameter was expanded from a parameter pack, or shall be a function parameter pack.

[Note 2:

A default argument cannot be redefined by a later declaration (not even to the same value) ([basic.def.odr]).

— _end note_]

[Example 2: void g(int = 0, ...); void f(int, int);void f(int, int = 7);void h() { f(3); void f(int = 1, int); } void m() { void f(int, int); f(4); void f(int, int = 5); f(4); void f(int, int = 5); } void n() { f(6); } template<class ... T> struct C { void f(int n = 0, T...);}; C<int> c; — _end example_]

For a given inline function defined in different translation units, the accumulated sets of default arguments at the end of the translation units shall be the same; no diagnostic is required.

If a friend declaration D specifies a default argument expression, that declaration shall be a definition and there shall be no other declaration of the function or function template which is reachable from D or from which D is reachable.

The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics ([dcl.init]).

The names in the default argument are looked up, and the semantic constraints are checked, at the point where the default argument appears, except that an immediate invocation ([expr.const]) that is a potentially-evaluated subexpression ([intro.execution]) of the initializer-clause in a parameter-declaration is neither evaluated nor checked for whether it is a constant expression at that point.

Name lookup and checking of semantic constraints for default arguments of templated functions are performed as described in [temp.inst].

[Example 3:

In the following code,gwill be called with the valuef(2):int a = 1;int f(int);int g(int x = f(a)); void h() { a = 2;{ int a = 3; g(); } }

— _end example_]

[Note 3:

A default argument is a complete-class context ([class.mem]).

Access checking applies to names in default arguments as described in [class.access].

— _end note_]

Except for member functions of templated classes, the default arguments in a member function definition that appears outside of the class definition are added to the set of default arguments provided by the member function declaration in the class definition; the program is ill-formed if a default constructor ([class.default.ctor]), copy or move constructor ([class.copy.ctor]), or copy or move assignment operator ([class.copy.assign]) is so declared.

Default arguments for a member function of a templated class shall be specified on the initial declaration of the member function within the templated class.

[Example 4: class C { void f(int i = 3);void g(int i, int j = 99);};void C::f(int i = 3) {} void C::g(int i = 88, int j) {} — _end example_]

[Note 4:

A local variable cannot be odr-used ([basic.def.odr]) in a default argument.

— _end note_]

[Example 5: void f() { int i;extern void g(int x = i); extern void h(int x = sizeof(i)); } — _end example_]

[Note 5:

The keywordthiscannot appear in a default argument of a member function; see [expr.prim.this].

[Example 6: class A { void f(A* p = this) { } }; — _end example_]

— _end note_]

A default argument is evaluated each time the function is called with no argument for the corresponding parameter.

A parameter shall not appear as a potentially-evaluated expression in a default argument.

[Note 6:

Parameters of a function declared before a default argument are in scope and can hide namespace and class member names.

— _end note_]

[Example 7: int a;int f(int a, int b = a); typedef int I;int g(float I, int b = I(2)); int h(int a, int b = sizeof(a)); — _end example_]

A non-static member shall not appear in a default argument unless it appears as the id-expression of a class member access expression ([expr.ref]) or unless it is used to form a pointer to member ([expr.unary.op]).

[Example 8:

The declaration ofX​::​mem1()in the following example is ill-formed because no object is supplied for the non-static memberX​::​aused as an initializer.

int b;class X { int a;int mem1(int i = a); int mem2(int i = b); static int b;};

The declaration ofX​::​mem2()is meaningful, however, since no object is needed to access the static memberX​::​b.

Classes, objects, and members are described in [class].

— _end example_]

A default argument is not part of the type of a function.

[Example 9: int f(int = 0);void h() { int j = f(1);int k = f(); } int (*p1)(int) = &f;int (*p2)() = &f; — _end example_]

When an overload set contains a declaration of a function that inhabits a scope S, any default argument associated with any reachable declaration that inhabits Sis available to the call.

[Note 7:

The candidate might have been found through a using-declaratorfrom which the declaration that provides the default argument is not reachable.

— _end note_]

A virtual function call ([class.virtual]) uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object.

An overriding function in a derived class does not acquire default arguments from the function it overrides.

[Example 10: struct A { virtual void f(int a = 7);};struct B : public A { void f(int a);};void m() { B* pb = new B; A* pa = pb; pa->f(); pb->f(); } — _end example_]