[dcl.fct]

# 9 Declarations [[dcl]](./#dcl)

## 9.3 Declarators [[dcl.decl]](dcl.decl#dcl.fct)

### 9.3.4 Meaning of declarators [[dcl.meaning]](dcl.meaning#dcl.fct)

#### 9.3.4.6 Functions [dcl.fct]

[1](#1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3671)

In a declarationTD whereT may be empty andD has the form

D1 ( [*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") ) [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]")opt  
 [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]")opt [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")opt

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

- [(1.1)](#1.1)

  If the [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") of the [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") is a [*conversion-function-id*](class.conv.fct#nt:conversion-function-id "11.4.8.3 Conversion functions [class.conv.fct]"),
the *derived-declarator-type-list* is empty[.](#1.1.sentence-1)

- [(1.2)](#1.2)

  Otherwise, the *derived-declarator-type-list* is as appears in
the type â*derived-declarator-type-list* Tâ
of the contained[*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") in the declarationTD1[.](#1.2.sentence-1)

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

- [(1.3)](#1.3)

  If the [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") is present,T shall be the single [*type-specifier*](dcl.type.general#nt:type-specifier "9.2.9.1 General [dcl.type.general]") auto, andU is the type specified by the [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")[.](#1.3.sentence-1)

- [(1.4)](#1.4)

  Otherwise, if the declaration declares a conversion function,
see [[class.conv.fct]](class.conv.fct "11.4.8.3 Conversion functions")[.](#1.4.sentence-1)

- [(1.5)](#1.5)

  Otherwise, U is T[.](#1.5.sentence-1)

The type of the[*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") inD is
â*derived-declarator-type-list*noexceptopt function of parameter-type-list[*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]")opt [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]")opt returning Uâ, where

- [(1.6)](#1.6)

the parameter-type-list is derived from
the [*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") as described below and

- [(1.7)](#1.7)

the optional noexcept is present if and only if
the exception specification ([[except.spec]](except.spec "14.5 Exception specifications")) is non-throwing[.](#1.sentence-3)

Such a type is a [*function type*](#def:type,function "9.3.4.6 Functions [dcl.fct]")[.](#1.sentence-4)[75](#footnote-75 "As indicated by syntax, cv-qualifiers are a significant component in function return types.")

The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") appertains to the function type[.](#1.sentence-5)

[2](#2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3740)

[parameter-declaration-clause:](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")  
...  
[*parameter-declaration-list*](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]")opt  
[*parameter-declaration-list*](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]") , ...  
[*parameter-declaration-list*](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]") ...

[parameter-declaration-list:](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]")  
[*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")  
[*parameter-declaration-list*](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]") , [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")

[parameter-declaration:](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")  
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt thisopt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]")  
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]") = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")  
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt thisopt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") [*abstract-declarator*](dcl.name#nt:abstract-declarator "9.3.2 Type names [dcl.name]")opt  
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") [*abstract-declarator*](dcl.name#nt:abstract-declarator "9.3.2 Type names [dcl.name]")opt = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")

The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") in a [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") appertains to the parameter[.](#2.sentence-1)

[3](#3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3767)

The[*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") determines the arguments that can be specified, and their processing, when the function is called[.](#3.sentence-1)

[*Note [1](#note-1)*:

The[*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is used to convert the arguments specified on the function call;
see [[expr.call]](expr.call "7.6.1.3 Function call")[.](#3.sentence-2)

â *end note*]

If the[*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") is empty, the function takes no arguments[.](#3.sentence-3)

A parameter list consisting of a single unnamed non-object parameter of
non-dependent type void is equivalent to an empty parameter
list[.](#3.sentence-4)

Except for this special case, a parameter shall not have type cv void[.](#3.sentence-5)

A parameter with volatile-qualified type is deprecated;
see [[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types")[.](#3.sentence-6)

If the[*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")terminates with an ellipsis or a function parameter
pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates")), 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[.](#3.sentence-7)

Where syntactically correct and where â...â is not
part of an [*abstract-declarator*](dcl.name#nt:abstract-declarator "9.3.2 Type names [dcl.name]"),
â...â
is synonymous with
â, ...â[.](#3.sentence-8)

A [*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of the form[*parameter-declaration-list*](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]") ... is deprecated ([[depr.ellipsis.comma]](depr.ellipsis.comma "D.5 Non-comma-separated ellipsis parameters"))[.](#3.sentence-9)

[*Example [1](#example-1)*:

The declarationint printf(const char*, ...); declares a function that can be called with varying numbers and types of arguments[.](#3.sentence-10)

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*[.](#3.sentence-11)

â *end example*]

[*Note [2](#note-2)*:

The standard header [<cstdarg>](cstdarg.syn#header:%3ccstdarg%3e "17.14.2 Header <cstdarg> synopsis [cstdarg.syn]") contains a mechanism for accessing arguments passed using the ellipsis
(see [[expr.call]](expr.call "7.6.1.3 Function call") and [[support.runtime]](support.runtime "17.14 Other runtime support"))[.](#3.sentence-12)

â *end note*]

[4](#4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3833)

The type of a function is determined using the following rules[.](#4.sentence-1)

The type of each parameter (including function parameter packs) is
determined from its own [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))[.](#4.sentence-2)

After determining the type of each parameter, any parameterof type âarray of Tâ orof function type T is adjusted to be âpointer to Tâ[.](#4.sentence-3)

After producing the list of parameter types,
any top-level[*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]")*s* modifying a parameter type are deleted
when forming the function type[.](#4.sentence-4)

The resulting list of transformed parameter types
and the presence or absence of the ellipsis or a function parameter pack
is the function's[*parameter-type-list*](#def:parameter-type-list "9.3.4.6 Functions [dcl.fct]")[.](#4.sentence-5)

[*Note [3](#note-3)*:

This transformation does not affect the types of the parameters[.](#4.sentence-6)

For example, int(*)(const int p, decltype(p)*) andint(*)(int, const int*) are identical types[.](#4.sentence-7)

â *end note*]

[*Example [2](#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*]

[5](#5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3874)

An [*explicit-object-parameter-declaration*](#def:explicit-object-parameter-declaration "9.3.4.6 Functions [dcl.fct]") is
a [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") with a this specifier[.](#5.sentence-1)

An explicit-object-parameter-declaration shall appear only as
the first [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") of
a [*parameter-declaration-list*](#nt:parameter-declaration-list "9.3.4.6 Functions [dcl.fct]") of one of:

- [(5.1)](#5.1)

a declaration of
a member function or member function template ([[class.mem]](class.mem "11.4 Class members")), or

- [(5.2)](#5.2)

an explicit instantiation ([[temp.explicit]](temp.explicit "13.9.3 Explicit instantiation")) or
explicit specialization ([[temp.expl.spec]](temp.expl.spec "13.9.4 Explicit specialization")) of
a templated member function, or

- [(5.3)](#5.3)

a [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1 General [expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6 Lambda expressions"))[.](#5.sentence-2)

A [*member-declarator*](class.mem.general#nt:member-declarator "11.4.1 General [class.mem.general]") with an explicit-object-parameter-declaration
shall not include
a [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") or a [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") and
shall not be declared static or virtual[.](#5.sentence-3)

[*Example [3](#example-3)*: struct C {void f(this C& self); template <typename Self> 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<C>} â *end example*]

[6](#6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3912)

A function parameter declared with an explicit-object-parameter-declaration
is an [*explicit object parameter*](#def:parameter,explicit_object "9.3.4.6 Functions [dcl.fct]")[.](#6.sentence-1)

An explicit object parameter shall not be
a function parameter pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#6.sentence-2)

An [*explicit object member function*](#def:member_function,explicit_object "9.3.4.6 Functions [dcl.fct]") is a non-static member function
with an explicit object parameter[.](#6.sentence-3)

An [*implicit object member function*](#def:member_function,implicit_object "9.3.4.6 Functions [dcl.fct]") is a non-static member function
without an explicit object parameter[.](#6.sentence-4)

[7](#7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3922)

The [*object parameter*](#def:parameter,object "9.3.4.6 Functions [dcl.fct]") of a non-static member function is either
the explicit object parameter or
the implicit object parameter ([[over.match.funcs]](over.match.funcs "12.2.2 Candidate functions and argument lists"))[.](#7.sentence-1)

[8](#8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3927)

A [*non-object parameter*](#def:parameter,non-object "9.3.4.6 Functions [dcl.fct]") is a function parameter
that is not the explicit object parameter[.](#8.sentence-1)

The [*non-object-parameter-type-list*](#def:non-object-parameter-type-list "9.3.4.6 Functions [dcl.fct]") of a member function is
the parameter-type-list of that function with the explicit object parameter,
if any, omitted[.](#8.sentence-2)

[*Note [4](#note-4)*:

The non-object-parameter-type-list consists of
the adjusted types of all the non-object parameters[.](#8.sentence-3)

â *end note*]

[9](#9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3938)

A function type with a [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") or a[*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") (including a type denoted by[*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") ([[dcl.typedef]](dcl.typedef "9.2.4 The typedef specifier"), [[temp.param]](temp.param "13.2 Template parameters")))
shall appear only as:

- [(9.1)](#9.1)

the function type for a non-static member function,

- [(9.2)](#9.2)

the function type to which a pointer to member refers,

- [(9.3)](#9.3)

the top-level function type of a function typedef declaration
or [*alias-declaration*](dcl.pre#nt:alias-declaration "9.1 Preamble [dcl.pre]"),

- [(9.4)](#9.4)

the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") in the default argument of a[*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template parameters")),

- [(9.5)](#9.5)

the [*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") of a [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]") for a[*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]") ([[temp.arg.type]](temp.arg.type "13.4.2 Type template arguments")), or

- [(9.6)](#9.6)

the operand of a [*reflect-expression*](expr.reflect#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") ([[expr.reflect]](expr.reflect "7.6.2.10 The reflection operator"))[.](#9.sentence-1)

[*Example [4](#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*]

[10](#10)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3971)

The effect of a[*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") in a function declarator is not the same as
adding cv-qualification on top of the function type[.](#10.sentence-1)

In the latter case, the cv-qualifiers are ignored[.](#10.sentence-2)

[*Note [5](#note-5)*:

A function type that has a [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]") is not a
cv-qualified type; there are no cv-qualified function types[.](#10.sentence-3)

â *end note*]

[*Example [5](#example-5)*: typedef void F();struct S {const F f; // OK, equivalent to: void f();}; â *end example*]

[11](#11)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L3990)

The return type, the parameter-type-list, the [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]"),
the [*cv-qualifier-seq*](dcl.decl.general#nt:cv-qualifier-seq "9.3.1 General [dcl.decl.general]"), and
the exception specification,
but not the default arguments ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))
or the trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[dcl.decl]](dcl.decl "9.3 Declarators")),
are part of the function type[.](#11.sentence-1)

[*Note [6](#note-6)*:

Function types are checked during the assignments and initializations of
pointers to functions, references to functions, and pointers to member functions[.](#11.sentence-2)

â *end note*]

[12](#12)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4002)

[*Example [6](#example-6)*:

The declarationint fseek(FILE*, long, int); declares a function taking three arguments of the specified types,
and returningint ([[dcl.type]](dcl.type "9.2.9 Type specifiers"))[.](#12.sentence-1)

â *end example*]

[13](#13)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4013)

[*Note [7](#note-7)*:

A single name can be used for several different functions in a single scope;
this is function overloading ([[over]](over "12 Overloading"))[.](#13.sentence-1)

â *end note*]

[14](#14)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4020)

The return type shall be a non-array object type, a reference type, or cv void[.](#14.sentence-1)

[*Note [8](#note-8)*:

An array of placeholder type is considered an array type[.](#14.sentence-2)

â *end note*]

[15](#15)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4028)

A volatile-qualified return type is deprecated;
see [[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types")[.](#15.sentence-1)

[16](#16)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4032)

Types shall not be defined in return or parameter types[.](#16.sentence-1)

[17](#17)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4035)

A typedef of function type may be used to declare a function but shall not be
used to define a function ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions"))[.](#17.sentence-1)

[*Example [7](#example-7)*: typedef void F();
F fv; // OK, equivalent to void fv(); F fv { } // errorvoid fv() { } // OK, definition of fv â *end example*]

[18](#18)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4048)

An identifier can optionally be provided as a parameter name;
if present in a function definition ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions")), it names a parameter[.](#18.sentence-1)

[*Note [9](#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[.](#18.sentence-2)

â *end note*]

[19](#19)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4057)

[*Example [8](#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[.](#19.sentence-1)

It is especially useful to comparefpi andpif[.](#19.sentence-2)

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[.](#19.sentence-3)

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[.](#19.sentence-4)

â *end example*]

[*Note [10](#note-10)*:

Typedefs and [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]")*s* are sometimes convenient when the return type of a function is complex[.](#19.sentence-5)

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

A [*trailing-return-type*](dcl.decl.general#nt:trailing-return-type "9.3.1 General [dcl.decl.general]") is most useful for a type that would be more complicated to specify before the [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]"):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*]

[20](#20)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4130)

A [*non-template function*](#def:function,non-template "9.3.4.6 Functions [dcl.fct]") is a function that is not a function template
specialization[.](#20.sentence-1)

[*Note [11](#note-11)*:

A function template is not a function[.](#20.sentence-2)

â *end note*]

[21](#21)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4137)

An [*abbreviated function template*](#def:template,function,abbreviated "9.3.4.6 Functions [dcl.fct]") is a function declaration that has
one or more generic parameter type placeholders ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers"))[.](#21.sentence-1)

An abbreviated function template is equivalent to
a function template ([[temp.fct]](temp.fct "13.7.7 Function templates"))
whose [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") includes
one invented [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]") for each generic parameter type placeholder
of the function declaration, in order of appearance[.](#21.sentence-2)

For a [*placeholder-type-specifier*](dcl.spec.auto.general#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]") of the form auto,
the invented parameter is
an unconstrained [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]")[.](#21.sentence-3)

For a [*placeholder-type-specifier*](dcl.spec.auto.general#nt:placeholder-type-specifier "9.2.9.7.1 General [dcl.spec.auto.general]") of the form[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") auto,
the invented parameter is a [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]") with
that [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")[.](#21.sentence-4)

The invented [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]") declares
a template parameter pack
if the corresponding [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") declares a function parameter pack[.](#21.sentence-5)

If the placeholder contains decltype(auto),
the program is ill-formed[.](#21.sentence-6)

The adjusted function parameters of an abbreviated function template
are derived from the [*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") by
replacing each occurrence of a placeholder with
the name of the corresponding invented [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]")[.](#21.sentence-7)

[*Example [9](#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[.](#21.sentence-9)

template<> void g1<int>(const int*, const double&); // OK, specialization of g1<int, const double> â *end example*]

[22](#22)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4190)

An abbreviated function template can have a [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")[.](#22.sentence-1)

The invented [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]")*s* are
appended to the [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") after
the explicitly declared [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s*[.](#22.sentence-2)

[*Example [10](#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[.](#22.sentence-3)

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*]

[23](#23)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4214)

A function declaration at block scope
shall not declare an abbreviated function template[.](#23.sentence-1)

[24](#24)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4218)

A [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") or [*abstract-declarator*](dcl.name#nt:abstract-declarator "9.3.2 Type names [dcl.name]") containing an ellipsis shall only
be used in a [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")[.](#24.sentence-1)

When it is part of a[*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]"),
the [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") declares a
function parameter pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#24.sentence-2)

Otherwise, the [*parameter-declaration*](#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") is part of a[*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") and declares a
template parameter pack; see [[temp.param]](temp.param "13.2 Template parameters")[.](#24.sentence-3)

A function parameter pack is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#24.sentence-4)

[*Example [11](#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*]

[25](#25)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4243)

There is a syntactic ambiguity when an ellipsis occurs at the end
of a [*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") without a preceding
comma[.](#25.sentence-1)

In this case, the ellipsis is parsed as part of the[*abstract-declarator*](dcl.name#nt:abstract-declarator "9.3.2 Type names [dcl.name]") 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*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")[.](#25.sentence-2)[76](#footnote-76 "One can explicitly disambiguate the parse either by introducing a comma (so the ellipsis will be parsed as part of the parameter-declaration-clause) or by introducing a name for the parameter (so the ellipsis will be parsed as part of the declarator-id).")

[75)](#footnote-75)[75)](#footnoteref-75)

As indicated by syntax, cv-qualifiers are a significant component in function return types[.](#footnote-75.sentence-1)

[76)](#footnote-76)[76)](#footnoteref-76)

One can explicitly disambiguate the parse either by
introducing a comma (so the ellipsis will be parsed as part of the[*parameter-declaration-clause*](#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")) or by introducing a name for the
parameter (so the ellipsis will be parsed as part of the[*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]"))[.](#footnote-76.sentence-1)
