Spec-Zone.ru › C++

Объявление функции

Объявление функции вводит имя функции и ее тип. Определение функции связывает имя/тип функции с телом функции.

Объявление функции

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

noptr-declarator ( parameter-list ) cv (необязательно) ref  (необязательно) except (необязательно) attr (необязательно) (1)
noptr-declarator ( parameter-list ) cv (необязательно) ref  (необязательно) except (необязательно) attr (необязательно)
-> trailing
(2) (с C++11)

(см. Объявления для других форм синтаксиса declarator)

1) Стандартный синтаксис объявления функции.
2) Объявление типа возвращаемого значения с модификатором. В этом случае decl-specifier-seq должен содержать ключевое слово auto.
noptr-declarator - любой допустимый declarator, но если он начинается с *, &, или &&, он должен быть заключен в скобки.
parameter-list - может быть пустым, список параметров функции, разделенных запятыми (см. подробности ниже)
attr - (с C++11) список атрибутов. Эти атрибуты применяются к типу функции, а не к самой функции. Атрибуты для функции появляются после идентификатора в declarator и объединяются с атрибутами, которые появляются в начале объявления, если таковые имеются.
cv - квалификаторы const/volatile, разрешены только в объявлениях нестатических функций-членов
ref - (с C++11) квалификация ref, разрешена только в объявлениях нестатических функций-членов
except -

динамическая спецификация исключений

(до C++11)

либо динамическая спецификация исключений
либо спецификация noexcept

(с C++11)
(до C++17)

спецификация noexcept

(с C++17)

Обратите внимание, что спецификация исключений не является частью типа функции

(до C++17)
trailing - тип возвращаемого значения, полезно, если тип возвращаемого значения зависит от имен аргументов, например template<class T, class U> auto add(T t, U u) -> decltype(t + u); или сложное, например в auto fpif(int)->int(*)(int)

Как упоминалось в Объявлениях, после declarator может следовать requires-оператор, который объявляет связанные ограничения для функции, которые должны быть выполнены, чтобы функция была выбрана разрешением перегрузки. (пример: void f1(int a) requires true;) Обратите внимание, что связанное ограничение является частью подписи функции, но не частью типа функции.

(с C++20)

Определения функций могут сочетаться с другими определениями, где decl-specifier-seq допускает:

// declares an int, an int*, a function, and a pointer to a function
int a = 1, *p = NULL, f(), (*pf)(double);
// decl-specifier-seq is int
// declarator f() declares (but doesn't define)
//                a function taking no arguments and returning int
 
struct S
{
    virtual int f(char) const, g(int) &&; // declares two non-static member functions
    virtual int f(char), x; // compile-time error: virtual (in decl-specifier-seq)
                            // is only allowed in declarations of non-static
                            // member functions
};

Использование объекта типа с квалификатором volatile в качестве параметра или типа возвращаемого значения устарело.

(с C++20)

Тип возвращаемого значения функции не может быть типом функции или типом массива (но может быть указателем или ссылкой на эти типы).

Как и в любом объявлении, атрибуты, которые появляются перед объявлением и атрибуты, которые появляются сразу после идентификатора в declarator, оба применяются к объявляемому или определяемому объекту (в данном случае к функции):

[[noreturn]] void f [[noreturn]] (); // okay: both attributes apply to the function f

Однако атрибуты, которые появляются после declarator (в синтаксисе выше), применяются к типу функции, а не к самой функции:

void f() [[noreturn]]; // error: this attribute has no effect on the function itself
(с C++11)

Вывод типа возвращаемого значения

Если decl-specifier-seq объявления функции содержит ключевое слово auto, тип возвращаемого значения может быть опущен, и компилятор выведет его из типа выражения, используемого в операторе return. Если тип возвращаемого значения не использует decltype(auto), вывод происходит по правилам вывода шаблонов аргументов:

int x = 1;
auto f() { return x; }        // return type is int
const auto& f() { return x; } // return type is const int&

Если тип возвращаемого значения является decltype(auto), тип возвращаемого значения будет таким же, каким бы он стал, если выражение, используемое в операторе return, было заключено в decltype:

int x = 1;
decltype(auto) f() { return x; }  // return type is int, same as decltype(x)
decltype(auto) f() { return(x); } // return type is int&, same as decltype((x))

(примечание: "const decltype(auto)&" - ошибка, decltype(auto) должен использоваться самостоятельно)

Если есть несколько операторов return, они все должны выводить один и тот же тип:

auto f(bool val)
{
    if (val) return 123; // deduces return type int
    else return 3.14f;   // error: deduces return type float
}

Если оператор return отсутствует или если аргумент оператора return - это выражение void, объявленный тип возвращаемого значения должен быть либо decltype(auto), в этом случае выведенный тип возвращаемого значения - void, или (возможно, с квалификатором cv) auto, в этом случае выведенный тип возвращаемого значения тогда (тождественно с квалификатором cv) void:

auto f() {}              // returns void
auto g() { return f(); } // returns void
auto* x() {}             // error: cannot deduce auto* from void

После того, как оператор return был увиден в функции, выведенный тип возвращаемого значения из этого оператора может быть использован в остальной части функции, включая в других операторах return:

auto sum(int i)
{
    if (i == 1)
        return i;              // sum’s return type is int
    else
        return sum(i - 1) + i; // okay: sum’s return type is already known
}

Если оператор return использует braced-init-list, вывод не разрешен:

auto func() { return {1, 2, 3}; } // error

Виртуальные функции и корутины(с C++20) не могут использовать вывод типа возвращаемого значения:

struct F
{
    virtual auto f() { return 2; } // error
};

Шаблоны функций, кроме функций пользовательского преобразования, могут использовать вывод типа возвращаемого значения. Вывод происходит при инстанциировании, даже если выражение в операторе return не является зависимым. Это инстанциирование не находится в непосредственном контексте для целей SFINAE.

template<class T>
auto f(T t) { return t; }
typedef decltype(f(1)) fint_t;    // instantiates f<int> to deduce return type
 
template<class T>
auto f(T* t) { return *t; }
void g() { int (*p)(int*) = &f; } // instantiates both fs to determine return types,
                                  // chooses second template overload

Переопределения или специализации функций или шаблонов функций, которые используют вывод типа возвращаемого значения, должны использовать те же заменители типа возвращаемого значения:

auto f(int num) { return num; }
// int f(int num);            // error: no placeholder return type
// decltype(auto) f(int num); // error: different placeholder
 
template<typename T>
auto g(T t) { return t; }
template auto g(int);     // okay: return type is int
// template char g(char); // error: not a specialization of the primary template g

Аналогично, переопределения или специализации функций или шаблонов функций, которые не используют вывод типа возвращаемого значения, не должны использовать заполнитель:

int f(int num);
// auto f(int num) { return num; } // error: not a redeclaration of f
 
template<typename T>
T g(T t) { return t; }
template int g(int);      // okay: specialize T as int
// template auto g(char); // error: not a specialization of the primary template g

Явные объявления инстанцирования сами по себе не инстанцируют шаблоны функций, которые используют вывод типа возвращаемого значения:

template<typename T>
auto f(T t) { return t; }
extern template auto f(int); // does not instantiate f<int>
 
int (*p)(int) = f; // instantiates f<int> to determine its return type,
                   // but an explicit instantiation definition 
                   // is still required somewhere in the program
(с C++14)

Список параметров

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

attr (необязательно) decl-specifier-seq declarator (1)
attr (необязательно) decl-specifier-seq declarator = initializer (2)
attr (необязательно) decl-specifier-seq abstract-declarator (необязательно) (3)
attr (необязательно) decl-specifier-seq abstract-declarator (необязательно) = initializer (4)
void (5)
1) Объявляет именованный (формальный) параметр. Для значений decl-specifier-seq и declarator, см. объявления.
int f(int a, int* p, int (*(*x)(double))[3]);
2) Объявляет именованный (формальный) параметр со значением по умолчанию.
int f(int a = 7, int* p = nullptr, int (*(*x)(double))[3] = nullptr);
3) Объявляет безымянный параметр.
int f(int, int*, int (*(*)(double))[3]);
4) Объявляет безымянный параметр со значением по умолчанию.
int f(int = 7, int* = nullptr, int (*(*)(double))[3] = nullptr);
5) Указывает, что функция не принимает параметров; это точное синоним пустого списка параметров: int f(void); и int f(); объявляют одну и ту же функцию. Обратите внимание, что тип void (возможно, с квалификаторами cv) не может использоваться в списке параметров иначе: int f(void, int); и int f(const void); являются ошибками (хотя производные типы, такие как void* могут быть использованы). В шаблоне может использоваться только независимый тип void (функция, принимающая один параметр типа T не становится функцией без параметров, если она инстанцирована с T = void)

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

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

Для совместимости с C89, необязательная запятая может появляться перед эллипсом, если список параметров содержит по крайней мере один параметр:

int printf(const char* fmt, ...); // OK, same as above

Хотя decl-specifier-seq подразумевает, что могут существовать спецификаторы помимо спецификаторов типов, единственный другой допустимый спецификатор — register а также auto(до C++11), и он не оказывает никакого влияния.

(до C++17)

Если какой-либо из параметров функции использует заполнитель (либо auto, либо тип концепции), объявление функции — это объявление сокращённого шаблона функции:

void f1(auto);    // same as template<class T> void f1(T)
void f2(C1 auto); // same as template<C1 T> void f2(T), if C1 is a concept
(начиная с C++20)

Имена параметров, объявленные в объявлениях функций, обычно служат только для самодокументирования. Они используются (но остаются необязательными) в определениях функций.

Тип каждого параметра функции в списке параметров определяется по следующим правилам:

1) Сначала decl-specifier-seq и спецификатор объединяются, как и в любом объявлении, чтобы определить тип.
2) Если тип — «массив T» или «массив неизвестной длины T», он заменяется на тип «указатель на T».
3) Если тип — тип функции F, он заменяется типом «указатель на F».
4) Квалификаторы cv верхнего уровня удаляются из типа параметра (эта корректировка влияет только на тип функции, но не изменяет свойство параметра: int f(const int p, decltype(p)*); и int f(int, const int*); объявляют одну и ту же функцию).

Из-за этих правил следующие объявления функций объявляют одну и ту же функцию:

int f(char s[3]);
int f(char[]);
int f(char* s);
int f(char* const);
int f(char* volatile s);

Следующие объявления также объявляют одну и ту же функцию:

int f(int());
int f(int (*g)());

Возникает неоднозначность в списке параметров, когда имя типа вложенно в скобки (включая лямбда-выражения)(начиная с C++11). В этом случае выбор между объявлением параметра типа указатель на функцию и объявлением параметра с избыточными скобками вокруг идентификатора declarator. Решение состоит в том, чтобы рассматривать имя типа как простой спецификатор типа (который является типом указателя на функцию):

class C {};
 
void f(int(C)) {} // void f(int(*fp)(C param)) {}
                  // NOT void f(int C) {}
 
void g(int *(C[10])); // void g(int *(*fp)(C param[10]));
                      // NOT void g(int *C[10]);

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

Эллипс, указывающий на переменное число аргументов, не должен предваряться запятой, даже если он следует за эллипсом, указывающим на расширение пакета параметров, поэтому следующие шаблоны функций являются идентичными:

template<typename... Args>
void f(Args..., ...);
 
template<typename... Args>
void f(Args... ...);
 
template<typename... Args>
void f(Args......);

Пример использования такого объявления — возможное реализация std::is_function.

#include <cstdio>
 
template<typename... Variadic, typename... Args>
constexpr void invoke(auto (*fun)(Variadic......), Args... args)
{
    fun(args...);
}
 
int main()
{
    invoke(std::printf, "%dm•%dm•%dm = %d%s%c", 2,3,7, 2*3*7, "m³", '\n');
}

Вывод:

2m•3m•7m = 42m³
(начиная с C++11)

Тип функции

Список типов параметров

Список типов параметров функции определяется следующим образом:

  1. Тип каждого параметра (включая пакеты параметров функций)(начиная с C++11) определяется из его собственного объявления параметра.
  2. После определения типа каждого параметра любой параметр типа «массив T» или типа функции T корректируется, чтобы быть «указателем на T».
  3. После создания списка типов параметров любые квалификаторы cv верхнего уровня, изменяющие тип параметра, удаляются при формировании типа функции.
  4. Получившийся список преобразованных типов параметров и наличие или отсутствие эллипса или функции пакета параметров(начиная с C++11) — это список типов параметров функции.
void f(char*);         // #1
void f(char[]) {}      // defines #1
void f(const char*) {} // OK, another overload
void f(char* const) {} // error: redefines #1
 
void g(char(*)[2]);   // #2
void g(char[3][2]) {} // defines #2
void g(char[3][3]) {} // OK, another overload
 
void h(int x(const int)); // #3
void h(int (*)(int)) {}   // defines #3

Определение типа функции

В синтаксисе (1), предполагая noptr-declarator как самостоятельное объявление, учитывая тип qualified-id или unqualified-id в noptr-declarator как «список типов производных деклараторов T»:

  • Если спецификация исключений — не выбрасывающая исключения, тип объявленной функции —
    «список типов производных деклараторов noexcept функция с
    списком типов параметров cv (необязательно) ref  (необязательно) возвращающая T».
(начиная с C++17)
  • В(до C++17)В противном случае, (начиная с C++17) тип объявленной функции —
    «список типов производных деклараторов функция с
    списком типов параметров cv (необязательно) ref  (необязательно)(начиная с C++11) возвращающая T».

В синтаксисе (2), предполагая noptr-declarator как самостоятельное объявление, учитывая тип qualified-id или unqualified-id в noptr-declarator как «список типов производного декларатора T» (T должен быть auto в этом случае):

  • Если спецификация исключения не выбрасывает исключения, тип объявленной функции —
    «список типов производного декларатора noexcept функция от
    списка типов параметров cv (необязательно) ref  (необязательно) возвращающая trailing ».
(с C++17)
  • Тип(до C++17)В противном случае тип(с C++17) объявленной функции —
    «список типов производного декларатора функция от
    списка типов параметров cv (необязательно) ref  (необязательно) возвращающая trailing ».
(с C++11)

attr, если присутствует, применяется к типу функции.

(с C++11)
// the type of “f1” is
// “function of int returning void, with attribute noreturn”
void f1(int a) [[noreturn]];
 
// the type of “f2” is
// “constexpr noexcept function of pointer to int returning int”
constexpr auto f2(int[] b) noexcept -> int;
 
struct X
{
    // the type of “f3” is
    // “function of no parameter const returning const int”
    const int f3() const;
};

Последовательные квалификаторы

Тип функции с cv  или ref  (с C++11) (включая тип, именованный именем typedef) может появляться только как:

  • тип функции для нестатического метода-члена,
  • тип функции, к которому относится указатель на член,
  • тип функции верхнего уровня объявления функции typedef или объявления псевдонима типа(с C++11),
  • идентификатор типа в аргументе по умолчанию шаблона параметра типа, или
  • идентификатор типа аргумента шаблона для параметра типа шаблона.
typedef int FIC(int) const;
FIC f;     // Error: does not declare a member function
 
struct S
{
    FIC f; // OK
};
 
FIC S::*pm = &S::f; // OK

Определение функции

Определение нечленной функции может появляться только в области видимости пространства имен (вложенных функций нет). Определение метода-члена также может появляться в теле определения класса. У них следующий синтаксис:

attr (необязательно) decl-specifier-seq (необязательно) declarator virt-specifier-seq (необязательно) function-body

где function-body — одно из следующих

ctor-initializer (необязательно) compound-statement (1)
function-try-block (2)
= delete ; (3) (с C++11)
= default ; (4) (с C++11)
1) Тело обычной функции.
2) Блок-функция try (обычное тело функции, заключенное в блок try/catch).
3) Явно удаленное определение функции.
4) Явно заданное по умолчанию определение функции, разрешено только для специальных методов-членов и операторов сравнения(с C++20).
attr - (с C++11) список атрибутов. Эти атрибуты комбинируются с атрибутами после идентификатора в declarator (см. верхнюю часть этой страницы), если таковые имеются.
decl-specifier-seq - тип возвращаемого значения со спецификаторами, как в грамматике объявления
declarator - декларатор функции, такой же, как в грамматике объявления функции выше (может быть заключён в скобки). как и в случае с объявлением функции, за ним может следовать requires-clause(с C++20)
virt-specifier-seq - (с C++11) override, final или их комбинация в любом порядке (разрешается только для нестатических методов-членов)
ctor-initializer - список инициализаторов членов, разрешается только в конструкторах
compound-statement - заключённая в фигурные скобки последовательность операторов, которая образует тело функции
int max(int a, int b, int c)
{
    int m = (a > b) ? a : b;
    return (m > c) ? m : c;
}
 
// decl-specifier-seq is "int"
// declarator is "max(int a, int b, int c)"
// body is { ... }

Тело функции — сложный оператор (последовательность нуля или более операторов, заключённая в пару фигурных скобок), который выполняется при вызове функции.

Типы параметров, а также тип возвращаемого значения определения функции не могут быть (возможно, квалифицированными cv) неполными типами классов за исключением случаев, когда функция определена как удалённая(с C++11). Проверка полноты выполняется только в теле функции, что позволяет методам-членам возвращать класс, в котором они определены (или его включающий класс), даже если он неполный на момент определения (он полный в теле функции).

Параметры, объявленные в declarator определения функции, находятся в области видимости в теле. Если параметр не используется в теле функции, его не нужно называть (достаточно использовать абстрактный декларатор):

void print(int a, int) // second parameter is not used
{
    std::printf("a = %d\n", a);
}

Несмотря на то, что верхнеуровневые cv-квалификаторы параметров отбрасываются в объявлениях функций, они изменяют тип параметра, как он виден в теле функции:

void f(const int n) // declares function of type void(int)
{
    // but in the body, the type of n is const int
}

Удаленные функции

Если вместо тела функции используется специальный синтаксис = delete;, функция определена как явным образом удаленная. Любое использование удаленной функции является ошибочным (программа не будет компилироваться). Это включает в себя вызовы, как явные (с оператором вызова функции), так и неявные (вызов удаленного перегруженного оператора, специального члена-функции, функции выделения памяти и т. д.), создание указателя или указателя на член на удаленную функцию, а также использование удаленной функции в выражении, которое не является потенциально вычисляемым. Однако, неявное ODR-использование нечистой виртуальной функции-члена, которая случайно является удаленной, разрешено.

Если функция перегружена, сначала выполняется разрешение перегрузки, и программа будет ошибочной только в том случае, если была выбрана удаленная функция:

struct sometype
{
    void* operator new(std::size_t) = delete;
    void* operator new[](std::size_t) = delete;
};
sometype* p = new sometype; // error: attempts to call deleted sometype::operator new

Удаленное определение функции должно быть первым объявлением в единице трансляции: ранее объявленная функция не может быть повторно объявлена как удаленная:

struct sometype { sometype(); };
sometype::sometype() = delete; // error: must be deleted on the first declaration

Пользовательские функции

Функция является пользовательской, если она объявлена пользователем и не явным образом задана по умолчанию или удалена при первом объявлении. Пользовательская функция, явно заданная по умолчанию (т. е. заданная по умолчанию после первого объявления), определяется в момент её явного задания по умолчанию; если такая функция неявно определена как удаленная, программа является ошибочной. Объявление функции как заданной по умолчанию после её первого объявления может обеспечить эффективное выполнение и лаконичное определение, одновременно обеспечивая стабильный двоичный интерфейс для развивающегося кода.

// All special member functions of “trivial” are
// defaulted on their first declarations respectively,
// they are not user-provided
struct trivial
{
    trivial() = default;
    trivial(const trivial&) = default;
    trivial(trivial&&) = default;
    trivial& operator=(const trivial&) = default;
    trivial& operator=(trivial&&) = default;
    ~trivial() = default;
};
 
struct nontrivial
{
    nontrivial(); // first declaration
};
 
// not defaulted on the first declaration,
// it is user-provided and is defined here
nontrivial::nontrivial() = default;

__func__

Внутри тела функции, локальная предопределенная переменная __func__ определяется как если бы

static const char __func__[] = "function-name";

Эта переменная имеет область действия блока и статический срок жизни:

struct S
{
    S(): s(__func__) {} // okay: initializer-list is part of function body
    const char* s;
};
void f(const char* s = __func__); // error: parameter-list is part of declarator
#include <iostream>
 
void Foo() { std::cout << __func__ << ' '; }
 
struct Bar
{
    Bar() { std::cout << __func__ << ' '; }
    ~Bar() { std::cout << __func__ << ' '; }
    struct Pub { Pub() { std::cout << __func__ << ' '; } };
};
 
int main()
{
    Foo();
    Bar bar;
    Bar::Pub pub;
}

Возможный вывод:

Foo Bar Pub ~Bar
(с C++11)

Примечания

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

Макрос проверки функций Значение Std Функция
__cpp_decltype_auto 201304L (C++14) decltype(auto)
__cpp_return_type_deduction 201304L (C++14) Вывод типа возвращаемого значения для обычных функций

Пример

#include <iostream>
#include <string>
 
// simple function with a default argument, returning nothing
void f0(const std::string& arg = "world!")
{
    std::cout << "Hello, " << arg << '\n';
}
 
// the declaration is in namespace (file) scope
// (the definition is provided later)
int f1();
 
// function returning a pointer to f0, pre-C++11 style
void (*fp03())(const std::string&)
{
    return f0;
}
 
// function returning a pointer to f0, with C++11 trailing return type
auto fp11() -> void(*)(const std::string&)
{
    return f0;
}
 
int main()
{
    f0();
    fp03()("test!");
    fp11()("again!");
    int f2(std::string) noexcept; // declaration in function scope
    std::cout << "f2(\"bad\"): " << f2("bad") << '\n';
    std::cout << "f2(\"42\"): " << f2("42") << '\n';
}
 
// simple non-member function returning int
int f1()
{
    return 007;
}
 
// function with an exception specification and a function try block
int f2(std::string str) noexcept
try
{
    return std::stoi(str);
}
catch (const std::exception& e)
{
    std::cerr << "stoi() failed!\n";
    return 0;
}

Возможный вывод:

stoi() failed!
Hello, world!
Hello, test!
Hello, again!
f2("bad"): 0
f2("42"): 42

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применимо к Поведение, опубликованное в стандарте Правильное поведение
CWG 135 C++98 функции-члены, определенные в классе,
не могли иметь параметр или возвращать
свой собственный класс, потому что он был неполным
разрешено
CWG 332 C++98 параметр мог иметь cv-квалифицированный тип void запрещено
CWG 393 C++98 типы, включающие указатели/ссылки на
массивы неизвестной длины, не могли быть параметрами
такие типы разрешены
CWG 452 C++98 список инициализаторов членов не являлся частью тела функции стал частью тела функции,
изменив синтаксис определения
функции
CWG 577 C++98 зависимый тип void мог использоваться для
объявления функции без параметров
разрешен только независящий
void
CWG 1327 C++11 функции по умолчанию или удаленные не могли
быть указаны с override или final
разрешено
CWG 1355 C++11 только специальные функции-члены могли быть пользовательскими распространено на все функции
CWG 1394 C++11 удаленные функции не могли иметь никаких параметров неполного типа или возвращать неполный тип неполный тип разрешен
CWG 1824 C++98 проверка полноты типа параметра и
типа возврата функции могла быть сделана
вне контекста определения функции
проверка полноты осуществляется
только в контексте определения
функции
CWG 1877 C++14 вывод типа возвращаемого значения рассматривал return; как return void(); в этом случае просто выводится тип
возвращаемого значения как void
CWG 2015 C++11 неявное odr-использование удаленной
виртуальной функции было ошибочным
такие odr-использования освобождаются
от запрета использования
CWG 2044 C++14 вывод типа возвращаемого значения для функций, возвращающих void,
не удавался, если объявленный тип возвращаемого значения был decltype(auto)
правило вывода обновлено для обработки этого случая
CWG 2081 C++14 переобъявления функций могли использовать вывод типа возвращаемого значения, даже если исходное объявление его не использует не разрешено
CWG 2145 C++98 декларатор в определении функции не мог быть заключен в скобки разрешено
CWG 2259 C++11 правило разрешения неоднозначностей относительно имен типов в скобках не охватывало лямбда-выражения охвачено
CWG 2430 C++98 в определении функции-члена в определении класса,
тип этого класса не мог быть типом возврата или
типом параметра из-за разрешения CWG issue 1824
проверку полноты осуществлять только в теле функции

См. также

Документация C по Объявлению функций

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/function

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API