31 KiB
[dcl.fct]
9 Declarations [dcl]
9.3 Declarators [dcl.decl]
9.3.4 Meaning of declarators [dcl.meaning]
9.3.4.6 Functions [dcl.fct]
In a declarationTD whereT may be empty andD has the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt
a derived-declarator-type-list is determined as follows:
-
If the unqualified-id of the declarator-id is a conversion-function-id, the derived-declarator-type-list is empty.
-
Otherwise, the derived-declarator-type-list is as appears in the type âderived-declarator-type-list Tâ of the containeddeclarator-id in the declarationTD1.
The declared return type U of the function type is determined as follows:
-
If the trailing-return-type is present,T shall be the single type-specifier auto, andU is the type specified by the trailing-return-type.
-
Otherwise, if the declaration declares a conversion function, see [class.conv.fct].
-
Otherwise, U is T.
The type of thedeclarator-id inD is âderived-declarator-type-listnoexceptopt function of parameter-type-listcv-qualifier-seqopt ref-qualifieropt returning Uâ, where
the parameter-type-list is derived from the parameter-declaration-clause as described below and
the optional noexcept is present if and only if the exception specification ([except.spec]) is non-throwing.
Such a type is a function type.75
The optional attribute-specifier-seq appertains to the function type.
parameter-declaration-clause:
...
parameter-declaration-listopt
parameter-declaration-list , ...
parameter-declaration-list ...
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
attribute-specifier-seqopt thisopt decl-specifier-seq declarator
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt thisopt decl-specifier-seq abstract-declaratoropt
attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt = initializer-clause
The optional attribute-specifier-seq in a parameter-declaration appertains to the parameter.
Theparameter-declaration-clause determines the arguments that can be specified, and their processing, when the function is called.
[Note 1:
Theparameter-declaration-clause is used to convert the arguments specified on the function call; see [expr.call].
â end note]
If theparameter-declaration-clause is 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.
A parameter with volatile-qualified type is deprecated; see [depr.volatile.type].
If theparameter-declaration-clauseterminates 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 â, ...â.
A parameter-declaration-clause of the formparameter-declaration-list ... is deprecated ([depr.ellipsis.comma]).
[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 aconstchar*.
â end example]
[Note 2:
The standard header contains a mechanism for accessing arguments passed using the ellipsis (see [expr.call] and [support.runtime]).
â end note]
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 T is adjusted to be âpointer to Tâ.
After producing the list of parameter types, any top-levelcv-qualifiers 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*); // #1void f(char[]) {} // defines #1void f(const char*) {} // OK, another overloadvoid f(char const) {} // error: redefines #1void g(char()[2]); // #2void g(char[3][2]) {} // defines #2void g(char[3][3]) {} // OK, another overloadvoid h(int x(const int)); // #3void h(int (*)(int)) {} // defines #3 â end example]
An explicit-object-parameter-declaration is a parameter-declaration with a this specifier.
An explicit-object-parameter-declaration shall appear only as the first parameter-declaration of a parameter-declaration-list of one of:
a declaration of a member function or member function template ([class.mem]), or
an explicit instantiation ([temp.explicit]) or explicit specialization ([temp.expl.spec]) of a templated member function, or
a lambda-declarator ([expr.prim.lambda]).
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 void g(this Self&& self, int); void h(this C) const; // error: const not allowed here};
void test(C c) { c.f(); // OK, calls C::f c.g(42); // OK, calls C::g<C&> std::move(c).g(42); // OK, calls C::g} â 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]
A function type with a cv-qualifier-seq or aref-qualifier (including a type denoted bytypedef-name ([dcl.typedef], [temp.param])) shall appear only as:
the function type for a non-static member function,
the function type to which a pointer to member refers,
the top-level function type of a function typedef declaration or alias-declaration,
the type-id in the default argument of atype-parameter ([temp.param]),
the type-id of a template-argument for atype-parameter ([temp.arg.type]), or
the operand of a reflect-expression ([expr.reflect]).
[Example 4: typedef int FIC(int) const; FIC f; // error: does not declare a member functionstruct S { FIC f; // OK}; FIC S::*pm = &S::f; // OKconstexpr std::meta::info yeti = ^^void(int) const &; // OK â end example]
The effect of acv-qualifier-seq in 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; // OK, equivalent to: void 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]
A volatile-qualified return type is deprecated; see [depr.volatile.type].
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; // OK, equivalent to void fv(); F fv { } // errorvoid fv() { } // OK, definition of 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 pointerpi to an integer, a functionf taking no arguments and returning an integer, a functionfpi taking an integer argument and returning a pointer to an integer, a pointerpif to a function which takes two pointers to constant characters and returns an integer, a functionfpif taking an integer argument and returning a pointer to a function that takes an integer argument and returns an integer.
It is especially useful to comparefpi andpif.
The binding offpi(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 functionfpif above 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 template is 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-parameter for each generic parameter type placeholder of the function declaration, in order of appearance.
For a placeholder-type-specifier of the form auto, the invented parameter is an unconstrained type-parameter.
For a placeholder-type-specifier of the formtype-constraint auto, the invented parameter is a type-parameter with that type-constraint.
The invented type-parameter declares a template parameter pack if the corresponding parameter-declaration declares 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 concept C1 = /* ... /;template 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 void g4(T);
Abbreviated function templates can be specialized like all function templates.
template<> void g1(const int*, const double&); // OK, specialization of g1<int, const double> â end example]
An abbreviated function template can have a template-head.
The invented type-parameters are appended to the template-parameter-list after the explicitly declared template-parameters.
[Example 10: template 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 && Cvoid 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-declarator containing 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]).
Otherwise, the parameter-declaration is part of atemplate-parameter-list and declares a template parameter pack; see [temp.param].
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
As indicated by syntax, cv-qualifiers are a significant component in function return types.
One can explicitly disambiguate the parse either by introducing a comma (so the ellipsis will be parsed as part of theparameter-declaration-clause) or by introducing a name for the parameter (so the ellipsis will be parsed as part of thedeclarator-id).