函数声明
函数声明引入函数名及其类型。函数定义将函数名/类型与函数体关联起来。
内容 |
[编辑] 函数声明
函数声明可以出现在任何作用域中。类作用域中的函数声明引入一个类成员函数(除非使用了 friend 说明符),详情参见 成员函数 和 友元函数。
noptr-声明符 ( 形参列表 ) cv (可选) ref (可选) except (可选) attr (可选) |
(1) | ||||||||
noptr-声明符 ( 形参列表 ) cv (可选) ref (可选) except (可选) attr (可选)-> 尾随 |
(2) | (C++11 起) | |||||||
(参见 声明 中 声明符 语法的其他形式)
noptr-声明符 | - | 任何有效的 声明符,但如果它以 * 、& 或 && 开头,则必须用括号括起来。 | ||||||
形参列表 | - | 可能为空,函数形参的逗号分隔列表(详细信息见下文) | ||||||
attr | - | (C++11 起) 属性 的列表。这些属性应用于函数的类型,而不是函数本身。函数的属性出现在声明符内的标识符之后,并与声明开头出现的任何属性组合。 | ||||||
cv | - | const/volatile 限定,仅允许在非静态成员函数声明中使用 | ||||||
ref | - | (C++11 起) ref-限定,仅允许在非静态成员函数声明中使用 | ||||||
except | - |
| ||||||
尾随 | - | 尾随返回类型,如果返回类型取决于实参名称(例如 template<class T, class U> auto add(T t, U u) -> decltype(t + u);)或者很复杂(例如 auto fpif(int)->int(*)(int))时很有用 |
正如 声明 中提到的,声明符后可跟随 requires 子句,它为函数声明关联的 约束,为了通过重载决议选择函数,必须满足这些约束。(示例:void f1(int a) requires true;) 请注意,关联的约束是函数签名的一部分,但不是函数类型的一部分。 |
(C++20 起) |
函数声明符可以与其他声明符混合使用,其中 声明说明符序列 允许
// 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 起) |
函数的返回类型不能是函数类型或数组类型(但可以是这些类型的指针或引用)。
与任何声明一样,出现在声明之前的属性和紧跟声明符内标识符之后出现的属性都适用于被声明或定义的实体(在本例中,是函数) [[noreturn]] void f [[noreturn]] (); // OK: both attributes apply to the function f 但是,出现在声明符之后的属性(在上面的语法中)应用于函数的类型,而不是函数本身 void f() [[noreturn]]; // Error: this attribute has no effect on the function itself |
(C++11 起) |
返回类型推导如果函数声明的 decl-说明符序列 包含关键字 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 语句中使用的表达式包装在 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; // OK: sum’s return type is already known } 如果 return 语句使用 花括号括起来的初始化器列表,则不允许推导 auto func() { return {1, 2, 3}; } // Error 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); // OK: 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); // OK: 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-说明符序列 声明符 | (1) | ||||||||
attr (可选) |
(2) | (C++23 起) | |||||||
attr (可选) decl-说明符序列 声明符 = 初始化器 |
(3) | ||||||||
attr (可选) decl-说明符序列 抽象声明符 (可选) | (4) | ||||||||
attr (可选) |
(5) | (C++23 起) | |||||||
attr (可选) decl-说明符序列 抽象声明符 (可选) = 初始化器 |
(6) | ||||||||
void
|
(7) | ||||||||
不正确的用法 | 示例 |
---|---|
存在多个形参 | int f1(void, int); |
命名的 void 形参 | inf f2(void param); |
void 是 cv 限定的 | int f3(const void); |
void 是 依赖 的 | int f4(T); (其中 T 是 void) |
void 形参是 显式对象形参 (C++23 起) | int f5(this void); |
尽管 decl-说明符序列 暗示可能存在类型说明符以外的说明符,但唯一允许的其他说明符是 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 起) |
带有说明符 this 的形参声明(语法 (2)/(5))声明显式对象形参。 显式对象形参不能是 函数形参包,并且只能作为形参列表中第一个形参出现在以下声明中 带有显式对象形参的成员函数具有以下限制 struct C { void f(this C& self); // OK template<typename Self> void g(this Self&& self); // also OK for templates void p(this C) const; // Error: “const” not allowed here static void q(this C); // Error: “static” not allowed here void r(int, this C); // Error: an explicit object parameter // can only be the first parameter }; // void func(this C& self); // Error: non-member functions cannot have // an explicit object parameter |
(C++23 起) |
函数声明中声明的形参名称通常仅用于自文档化目的。它们在函数定义中使用(但仍然是可选的)。
当类型名称嵌套在括号中时,形参列表中会出现歧义 (包括 lambda 表达式)(C++11 起)。在这种情况下,选择是在声明指向函数的指针类型的形参和声明在 声明符 的标识符周围带有冗余括号的形参之间进行。解决方案是将类型名称视为简单类型说明符(即指向函数类型的指针)
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]);
形参类型不能是包含引用或指向未知边界数组的指针的类型,包括此类类型的多级指针/数组,或者是指向其形参是此类类型的函数的指针。
[编辑] 使用省略号
形参列表中的最后一个形参可以是省略号 (...);这声明了一个可变参数函数。可以省略省略号前的逗号(C++26 中已弃用)
int printf(const char* fmt, ...); // a variadic function int printf(const char* fmt...); // same as above, but deprecated since C++26 template<typename... Args> void f(Args..., ...); // a variadic function template with a parameter pack template<typename... Args> void f(Args... ...); // same as above, but deprecated since C++26 template<typename... Args> void f(Args......); // same as above, but deprecated since C++26
[编辑] 函数类型
[编辑] 形参类型列表
函数的形参类型列表按如下方式确定
- 每个形参的类型 (包括函数 形参包)(C++11 起) 是从其自身的 形参声明 中确定的。
- 在确定每个形参的类型之后,任何 “
T
数组” 或函数类型T
的形参都会被调整为 “指向T
的指针”。 - 在生成形参类型列表之后,在形成函数类型时,会删除修改形参类型的任何顶层 cv 限定符。
- 转换后的形参类型的结果列表以及 省略号 或函数 形参包(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-声明符 作为独立声明,给定 noptr-声明符 中 限定标识 或 非限定标识 的类型为 “derived-declarator-type-list T
”
|
(C++17 起) |
- (C++17 前)否则,(C++17 起) 声明的函数类型是
“derived-declarator-type-list 函数,它接受
形参类型列表 cv (可选) ref (可选)(C++11 起) 并返回T
”。
在语法 (2) 中,假设 noptr-声明符 作为独立声明,给定 noptr-声明符 中 限定标识 或 非限定标识 的类型为 “derived-declarator-type-list |
(C++11 起) |
|
(C++17 起) |
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
[编辑] 函数签名
每个函数都有一个签名。
函数的签名由其名称和 形参类型列表 组成。其签名还包含外围 命名空间,但以下情况除外:
- 如果函数是成员函数,则其签名包含函数所属的类,而不是外围命名空间。其签名还包含以下组件(如果存在):
- cv
|
(C++11 起) |
|
(C++20 起) |
except 和 attr(自 C++11 起) 不涉及函数签名,尽管 noexcept 说明符 影响函数类型(自 C++17 起)。
[编辑] 函数定义
非成员函数定义只能出现在命名空间作用域中(没有嵌套函数)。成员函数 定义也可以出现在 类定义 的主体中。它们具有以下语法:
attr (可选) decl-specifier-seq (可选) declarator virt-specs (可选) contract-specs (可选) function-body |
(1) | ||||||||
attr (可选) decl-specifier-seq (可选) declarator requires-clause contract-specs (可选) function-body |
(2) | (C++20 起) | |||||||
attr | - | (自 C++11 起) 属性 列表。这些属性与 declarator 中标识符之后的属性(如果有)组合在一起(参见本页顶部)。 |
decl-specifier-seq | - | 带有说明符的返回类型,如 声明语法 中所示 |
declarator | - | 函数声明符,与上面的函数声明语法相同(可以带括号) |
virt-specs | - | (自 C++11 起) override 、final 或它们的任意顺序组合 |
requires-clause | - | requires 子句 |
contract-specs | - | (自 C++26 起) 函数契约说明符 列表 |
function-body | - | 函数体(见下文) |
function-body 是以下之一:
ctor-initializer (可选) compound-statement | (1) | ||||||||
function-try-block | (2) | ||||||||
= default ; |
(3) | (C++11 起) | |||||||
= delete ; |
(4) | (C++11 起) | |||||||
= delete ( string-literal ); |
(5) | (自 C++26 起) | |||||||
ctor-initializer | - | 成员初始化列表,仅允许在构造函数中使用 |
compound-statement | - | 用花括号括起来的 语句序列,构成函数的主体 |
function-try-block | - | 一个 函数 try 块 |
string-literal | - | 一个 未求值的字符串字面量,可用于解释函数被删除的原因 |
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 { ... }
函数体是一个 复合语句(由一对花括号包围的零个或多个语句序列),在函数调用时执行。此外,构造函数 的函数体还包括以下内容:
- 对于所有标识符在构造函数的 成员初始化列表 中缺席的非静态数据成员, 默认成员初始化器 或(自 C++11 起) 用于初始化相应成员 子对象 的 默认初始化。
- 对于所有类型名称在构造函数的成员初始化列表中缺席的基类,用于初始化相应基类子对象的默认初始化。
如果函数定义包含 virt-specs,则它必须定义一个 成员函数。 |
(C++11 起) |
如果函数定义包含 requires-clause,则它必须定义一个 模板函数。 |
(C++20 起) |
void f() override {} // Error: not a member function void g() requires (sizeof(int) == 4) {} // Error: not a templated function
函数定义的形参类型以及返回类型不能是(可能带 cv 限定的)不完整 类类型,除非该函数被定义为 deleted(自 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 }
预置函数如果函数定义具有语法 (3),则该函数被定义为显式预置。 显式预置的函数必须是 特殊成员函数 或 比较运算符函数(自 C++20 起),并且它必须没有 默认实参。 显式预置的特殊成员函数
如果
在其首次声明中显式预置的函数是隐式 inline 的,并且如果它可以是 constexpr 函数,则它是隐式 constexpr 的。 struct S { S(int a = 0) = default; // error: default argument void operator=(const S&) = default; // error: non-matching return type ~S() noexcept(false) = default; // OK, different exception specification private: int i; S(S&); // OK, private copy constructor }; S::S(S&) = default; // OK, defines copy constructor 显式预置函数和隐式声明函数统称为预置函数。它们的实际定义将被隐式提供,请参阅其对应的页面以了解详细信息。 删除的函数如果函数定义具有语法 (4) 或 (5)(自 C++26 起),则该函数被定义为显式删除。 任何对已删除函数的使用都是非良构的(程序将无法编译)。这包括调用,显式调用(使用函数调用运算符)和隐式调用(调用已删除的重载运算符、特殊成员函数、分配函数等),构造指向已删除函数的指针或成员指针,甚至在不是 潜在求值 的表达式中使用已删除的函数。 非纯虚成员函数可以定义为 deleted,即使它是隐式 ODR 使用 的。已删除的函数只能被已删除的函数重写,而非删除的函数只能被非删除的函数重写。
如果函数被重载,则首先进行 重载决议,并且仅当选择了已删除的函数时,程序才是非良构的。 struct T { void* operator new(std::size_t) = delete; void* operator new[](std::size_t) = delete("new[] is deleted"); // since C++26 }; T* p = new T; // Error: attempts to call deleted T::operator new T* p = new T[5]; // Error: attempts to call deleted T::operator new[], // emits a diagnostic message “new[] is deleted” 函数的已删除定义必须是翻译单元中的第一个声明:先前声明的函数不能被重新声明为 deleted。 struct T { T(); }; T::T() = delete; // Error: must be deleted on the first declaration 用户提供的函数如果函数是用户声明的,并且在其首次声明中未显式预置或删除,则该函数是用户提供的。用户提供的显式预置函数(即,在其首次声明之后显式预置的函数)在其显式预置的点定义;如果此类函数被隐式定义为 deleted,则程序是非良构的。在函数的首次声明之后将其声明为预置可以提供高效的执行和简洁的定义,同时为不断发展的代码库启用稳定的二进制接口。 // 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; 歧义消除在以
using T = void(); // function type using U = int; // non-function type T a{}; // defines a function doing nothing U b{}; // value-initializes an int object T c = delete("hello"); // defines a function as deleted U d = delete("hello"); // copy-initializes an int object with // the result of a delete expression (ill-formed)
__func__在函数体内部,函数局部预定义变量 __func__ 的定义如同: static const char __func__[] = "function-name"; 此变量具有块作用域和静态存储持续时间。 struct S { S(): s(__func__) {} // OK: initializer-list is part of function body const char* s; }; void f(const char* s = __func__); // Error: parameter-list is part of declarator |
(C++11 起) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
函数契约说明符函数声明和 lambda 表达式 可以包含函数契约说明符 序列,每个说明符具有以下语法:
1) 引入前置条件断言 。
2,3) 引入后置条件断言 。
2) 断言不绑定到结果。
3) 断言绑定到结果。
函数契约断言是与函数关联的 契约断言。函数契约断言的谓词是其 predicate 上下文转换 为 bool。 以下函数不能使用函数契约说明符声明: 前置条件断言前置条件断言与进入函数关联。 int divide(int dividend, int divisor) pre(divisor != 0) { return dividend / divisor; } double square_root(double num) pre(num >= 0) { return std::sqrt(num); } 后置条件断言后置条件断言与正常退出函数关联。 如果后置条件断言具有 identifier ,则函数契约说明符引入 identifier 作为关联函数的结果绑定的名称。结果绑定表示该函数调用返回的对象或引用。结果绑定的类型是其关联函数的返回类型。 int absolute_value(int num) post(r : r >= 0) { return std::abs(num); } double sine(double num) post(r : r >= -1.0 && r <= 1.0) { if (std::isnan(num) || std::isinf(num)) // exiting via an exception never causes contract violation throw std::invalid_argument("Invalid argument"); return std::sin(num); } 如果后置条件断言具有 identifier ,并且关联函数的返回类型是(可能带 cv 限定的)void,则程序是非良构的。 void f() post(r : r > 0); // Error: no value can be bound to “r” 当非模板函数的声明返回类型包含 占位符类型 时,带有 identifier 的后置条件断言只能出现在函数定义中。 auto g(auto&) post(r : r >= 0); // OK, “g” is a template auto h() post(r : r >= 0); // Error: cannot name the return value auto k() post(r : r >= 0) // OK, “k” is a definition { return 0; } 契约一致性函数或函数模板 func 的 重新声明 如果声明 两个 contract-specs s 是相同的,如果它们由相同顺序的相同函数契约说明符组成。 函数声明
如果仅由于比较两个 lambda 表达式(它们包含在 predicate s 中)而未满足此条件,则不需要诊断。 bool b1, b2; void f() pre (b1) pre([]{ return b2; }()); void f(); // OK, function contract specifiers omitted void f() pre (b1) pre([]{ return b2; }()); // Error: closures have different types void f() pre (b1); // Error: function contract specifiers are different int g() post(r : b1); int g() post(b1); // Error: no result binding namespace N { void h() pre (b1); bool b1; void h() pre (b1); // Error: function contract specifiers differ // according to the one−definition rule } |
(自 C++26 起) |
[编辑] 注释
在使用直接初始化语法的变量声明和函数声明之间存在歧义的情况下,编译器始终选择函数声明;请参阅 直接初始化。
特性测试宏 | 值 | 标准 | 特性 |
---|---|---|---|
__cpp_decltype_auto |
201304L |
(C++14) | decltype(auto)
|
__cpp_return_type_deduction |
201304L |
(C++14) | 普通函数的返回类型推导 |
__cpp_explicit_this_parameter |
202110L |
(C++23) | 显式对象形参 (推导 this) |
__cpp_deleted_function |
202403L |
(C++26) | 带有原因的已删除函数 |
[编辑] 关键字
[编辑] 示例
#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; } // deleted function, an attempt to call it results in a compilation error void bar() = delete # if __cpp_deleted_function ("reason") # endif ;
可能的输出
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 | 如果声明的返回类型为 decltype(auto),则返回 void 的函数的返回类型推导将失败 |
更新了推导规则以处理这种情况 |
CWG 2081 | C++14 | 函数重新声明可以使用返回类型推导,即使初始声明不使用 |
不允许 |
CWG 2144 | C++11 | {} 在同一位置可能是函数体或初始化器 | 通过声明符标识符的类型来区分 |
CWG 2145 | C++98 | 函数定义中的 declarator 不能带括号 | 允许 |
CWG 2259 | C++11 | 关于带括号的类型名称的歧义消除规则不涵盖 lambda 表达式 |
已涵盖 |
CWG 2430 | C++98 | 在类定义中的成员函数定义中,由于 CWG issue 1824 的解决,该类的类型不能是返回类型或形参类型 |
仅在函数定义的上下文中检查 函数体 |
CWG 2760 | C++98 | 构造函数的函数体不包括构造函数的常规函数体中未指定的初始化 |
也包括这些初始化 |
CWG 2831 | C++20 | 带有 requires-clause 的函数定义可以定义非模板函数 |
禁止 |
CWG 2846 | C++23 | 显式对象成员函数不能具有类外定义 | 允许 |
CWG 2915 | C++23 | 未命名的显式对象形参可以具有 void 类型 | 禁止 |
[编辑] 参见
C 文档 关于 声明函数
|