[dcl.fct] (original) (raw)

9 Declarations [dcl.dcl]

9.3 Declarators [dcl.decl]

9.3.4 Meaning of declarators [dcl.meaning]

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.76

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 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.

[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_]

[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 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.

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 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.

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.77