11 Declarators [dcl.decl]

11.3 Meaning of declarators [dcl.meaning]

11.3.5 Functions [dcl.fct]

В декларации, T D где D есть форма

D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt

и тип, содержащийся declarator-id в объявлении, T D1 - «derived-declarator-type-list T», тип declarator-id in D - «derived-declarator-type-list noexceptopt функция возврата ( parameter-declaration-clause) », где необязательный элемент присутствует тогда и только тогда, когда он не выбрасывает. Необязательный параметр относится к типу функции.cv-qualifier-seqopt ref-qualifieroptTnoexcept exception specification attribute-specifier-seq

В декларации, T D где D есть форма

D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-type

и тип, содержащийся declarator-id в объявлении T D1 «derived-declarator-type-listT», T должен быть единственным type-specifierauto. Тип declarator-id in D - это «derived-declarator-type-list noexceptopt функция возврата ( parameter-declaration-clause) », где - тип, указанный в , и где необязательный параметр присутствует тогда и только тогда, когда спецификация исключения не выбрасывает. Необязательный параметр относится к типу функции.cv-qualifier-seqopt ref-qualifieroptUU trailing-return-typenoexcept attribute-specifier-seq

parameter-declaration-clause Определяет аргументы , которые могут быть определены, и их обработка, когда функция вызывается. [ Используется для преобразования аргументов , указанных в вызове функции; см . ] Если пусто, функция не принимает аргументов. Список параметров, состоящий из одного безымянного параметра независимого типа , эквивалентен пустому списку параметров. За исключением этого особого случая, у параметра не должно быть типа . Если завершается многоточием или a , количество аргументов должно быть равно или превышать количество параметров, которые не имеют аргумента по умолчанию и не являются пакетами параметров функции. Там, где синтаксически правильно и где « » не является частью , « » является синонимом « ». [ ДекларацияNote: parameter-declaration-clause[expr.call]end noteparameter-declaration-clausevoid cv voidparameter-declaration-clause function parameter pack...abstract-declarator, ......Example:

int printf(const char*, ...);

объявляет функцию, которую можно вызывать с различным числом и типами аргументов.

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

Однако первый аргумент должен иметь тип, который может быть преобразован в ] [ Стандартный заголовок содержит механизм доступа к аргументам, переданным с использованием многоточия (см. И ). ]const char* end exampleNote: <cstdarg> [expr.call] [support.runtime]end note

Одно имя может использоваться для нескольких различных функций в одной области; это функцияoverloading. Все объявления функции должны точно согласовываться как в типе возвращаемого значения, так и в списке типов-параметров. Тип функции определяется по следующим правилам. Тип каждого параметра (включая пакеты параметров функций) определяется его собственным decl-specifier-seq и declarator. После определения типа каждого параметра любой параметр типа «массивT» или типа функцииT корректируется как «указатель наT». После создания списка типов параметров любые изменения верхнего уровня, cv-qualifiers изменяющие тип параметра, удаляются при формировании типа функции. Результирующий список преобразованных типов параметров и наличие или отсутствие многоточия или пакета параметров функции - это функция parameter-type-list. [ Note: Это преобразование не влияет на типы параметров. Например,int(*)(const int p, decltype(p)*) и int(*)(int, const int*) идентичные типы. ]end note

Тип функции с символом a cv-qualifier-seqили a ref-qualifier(включая тип с именем typedef-name([dcl.typedef],[temp.param])) должен отображаться только как:

[Example:

typedef int FIC(int) const;
FIC f;              // ill-formed: does not declare a member function
struct S {
  FIC f;            // OK
};
FIC S::*pm = &S::f; // OK

end example]

Эффект от a cv-qualifier-seq в деклараторе функции отличается от добавления cv-квалификации поверх типа функции. В последнем случае cv-квалификаторы игнорируются. [ Note: Тип функции, имеющий a cv-qualifier-seq, не является типом cv; не существует типов функций с квалификацией cv. ] [end noteExample:

typedef void F();
struct S {
  const F f;        // OK: equivalent to: void f();
};

end example]

Тип возвращаемого значения, список типов-параметров, the ref-qualifier, the cv-qualifier-seqи спецификация исключения, но не thedefault arguments, являются частью типа функции. [ Note: Типы функций проверяются во время присвоения и инициализации указателей на функции, ссылок на функции и указателей на функции-члены. ]end note

[ ДекларацияExample:

int fseek(FILE*, long, int);

объявляет функцию, принимающую три аргумента указанных типов и возвращающую int ([dcl.type]). ]end example

Функции не должны иметь возвращаемый тип массива или функции типа, хотя они могут иметь возвращаемый тип указателя типа или ссылки на такие вещи. Массивов функций быть не должно, хотя могут быть массивы указателей на функции.

Типы не должны определяться в возвращаемых типах или типах параметров. Тип параметра или возвращаемый тип для определения функции не должен быть неполным (возможно, cv-квалифицированным) типом класса в контексте определения функции, если только функция не является deleted.

Typedef типа функции может использоваться для объявления функции, но не должен использоватьсяdefine a function. [Example:

typedef void F();
F  fv;              // OK: equivalent to void fv();
F  fv { }           // ill-formed
void fv() { }       // OK: definition of fv

end example]

Идентификатор может быть дополнительно предоставлен как имя параметра; если присутствует вfunction definition, он называет параметр. [ Note: В частности, имена параметров также являются необязательными в определениях функций и именах, используемых для параметра в разных объявлениях, и определение функции не обязательно должно быть одинаковым. Если имя параметра присутствует в объявлении функции, которое не является определением, его нельзя использовать вне декларатора функции, потому что это степень его потенциальной области видимости ([basic.scope.proto]). ]end note

[ Example: Декларация

int i,
    *pi,
    f(),
    *fpi(int),
    (*pif)(const char*, const char*),
    (*fpif(int))(int);

объявляет целое число i, указатель pi на целое число, функцию f , не принимающую аргументов и возвращающую целое число, функцию, fpi принимающую целочисленный аргумент и возвращающую указатель на целое число, указатель pif на функцию, которая принимает два указателя на постоянные символы и возвращает целое число , функция, fpif принимающая целочисленный аргумент и возвращающая указатель на функцию, которая принимает целочисленный аргумент и возвращает целое число. Особенно полезно сравнивать fpi и pif. Привязка *fpi(int) is *(fpi(int)), поэтому объявление предполагает, и та же конструкция в выражении требует вызова функцииfpi, а затем использования косвенного обращения через результат (указатель) для получения целого числа. В деклараторе (*pif)(const char*, const char*)дополнительные круглые скобки необходимы, чтобы указать, что косвенное обращение через указатель на функцию приводит к функции, которая затем вызывается. ] [ Typedefs и иногда удобен, когда тип возвращаемого значения функции сложный. Например, указанная выше функция могла быть объявленаend exampleNote: trailing-return-types fpif

typedef int  IFUNC(int);
IFUNC*  fpif(int);

или

auto fpif(int)->int(*)(int);

A trailing-return-typeнаиболее полезен для типа, который было бы сложнее указать перед declarator-id:

template <class T, class U> auto add(T t, U u) -> decltype(t + u);

скорее, чем

template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);

end note]

Anon-template function - это функция, которая не является специализацией шаблона функции. [ Note: Шаблон функции не является функцией. ]end note

A declarator-idили abstract-declarator содержащие многоточие должны использоваться только в parameter-declaration. Такой parameter-declarationвотparameter pack. Когда он является частью parameter-declaration-clause, пакет параметров - это function parameter pack. [ Note: В противном случае, parameter-declarationявляется частью a, template-parameter-listа пакет параметров является пакетом параметров шаблона; см[temp.param]. ] Пакет параметров функции - это файл . [end notepack expansionExample:

template<typename... T> void f(T (* ...t)(int, int));

int add(int, int);
float subtract(int, int);

void g() {
  f(add, subtract);
}

end example]

Возникает синтаксическая двусмысленность, когда многоточие стоит в конце a parameter-declaration-clauseбез предшествующей запятой. В этом случае многоточие анализируется как часть, abstract-declaratorесли тип параметра либо называет пакет параметров шаблона, который не был развернут, либо содержитauto; в противном случае он анализируется как часть parameter-declaration-clause.101

Как указано в синтаксисе, cv-квалификаторы являются важным компонентом в типах возвращаемых функций.

Можно явно устранить неоднозначность синтаксического анализа, введя запятую (так что многоточие будет анализироваться как часть parameter-declaration-clause) или введя имя для параметра (так, чтобы многоточие было проанализировано как часть declarator-id).