[dcl.fct] (original) (raw)
9 Declarations [dcl.dcl]
9.3 Declarators [dcl.decl]
9.3.3 Meaning of declarators [dcl.meaning]
9.3.3.5 Functions [dcl.fct]
The type of thedeclarator-idinDis “derived-declarator-type-list noexceptfunction of parameter-type-listcv-qualifier-seq ref-qualifierreturning U”, where
- the parameter-type-list is derived from the parameter-declaration-clause as described below,
- U is the type specified by the trailing-return-type, and
- the optional noexcept is present if and only if the exception specification is non-throwing.
Theparameter-declaration-clausedetermines the arguments that can be specified, and their processing, when the function is called.
[ Note
:
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 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
:
The declaration
int 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 owndecl-specifier-seqanddeclarator.
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-qualifiersmodifying 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
:
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
:
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
:
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
:
typedef void F();
struct S {
const F f;
};
— end example
]
[ Note
:
Function types are checked during the assignments and initializations of pointers to functions, references to functions, and pointers to member functions.
— end note
]
[ Example
:
The declaration
int fseek(FILE*, long, int);
declares a function taking three arguments of the specified types, and returningint ([dcl.type]).
— end example
]
A single name can be used for several different functions in a single scope; this is function overloading ([over]).
All declarations for a function shall have equivalent return types, parameter-type-lists, and requires-clauses ([temp.over.link]).
Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things.
There shall be no arrays of functions, although there can be arrays of pointers to functions.
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
:
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
:
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.
If a parameter name is present in a function declaration that is not a definition, it cannot be used outside of its function declarator because that is the extent of its potential scope ([basic.scope.param]).
— end note
]
[ Example
:
The declaration
int 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
:
Typedefs and trailing-return-types are sometimes convenient when the return type of a function is complex.
For example, the functionfpifabove could have been declared
typedef int IFUNC(int); IFUNC* fpif(int);
or
auto 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 than
template <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
:
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 template-parameterfor each generic parameter type placeholder of the function declaration, in order of appearance.
The invented type template-parameter is a template parameter pack if the corresponding parameter-declarationdeclares a function parameter pack ([dcl.fct]).
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 template-parameter.
[ Example
:
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);
These declarations are functionally equivalent (but not equivalent) to the following declarations.
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&);
— end example
]
An abbreviated function template can have a template-head.
The invented template-parameters are appended to the template-parameter-list after the explicitly declared template-parameters.
[ Example
:
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 && C void g(T x, U y, W z);
— end example
]
A function declaration at block scope shall not declare an abbreviated function template.
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
:
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.88