函数声明
函数声明引入函数名及其类型。函数定义将函数名/类型与函数体关联起来。
目录 |
[编辑] 函数声明
函数声明可以出现在任何作用域中。类作用域中的函数声明引入一个类成员函数(除非使用了 friend 说明符),详情请参见成员函数和友元函数。
noptr-declarator ( parameter-list ) cv (可选) ref (可选) except (可选) attr (可选) |
(1) | ||||||||
noptr-declarator ( parameter-list ) cv (可选) ref (可选) except (可选) attr (可选)-> trailing |
(2) | (C++11 起) | |||||||
(declarator 语法的其他形式请参见声明)
noptr-declarator | - | 任何有效的 declarator,但如果它以 * 、& 或 && 开头,则必须用括号括起来。 | ||||||
parameter-list | - | 可能为空的,逗号分隔的函数参数列表(详情请参见下文) | ||||||
属性 | - | (C++11 起) 一个属性列表。这些属性应用于函数类型,而非函数本身。函数的属性出现在声明符中标识符之后,并与声明开头出现的任何属性(如果有)相结合。 | ||||||
cv | - | const/volatile 限定符,仅允许在非静态成员函数声明中使用 | ||||||
ref | - | (C++11 起) ref 限定符,仅允许在非静态成员函数声明中使用 | ||||||
异常规范 | - |
| ||||||
trailing | - | 尾随返回类型,在返回类型取决于参数名时很有用,例如 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-qualified 对象类型作为参数类型或返回类型已被弃用。 |
(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-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),则返回类型与 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-specifier-seq declarator | (1) | ||||||||
attr (可选) |
(2) | (C++23 起) | |||||||
attr (可选) decl-specifier-seq declarator = initializer |
(3) | ||||||||
attr (可选) decl-specifier-seq abstract-declarator (可选) | (4) | ||||||||
attr (可选) |
(5) | (C++23 起) | |||||||
attr (可选) decl-specifier-seq abstract-declarator (可选) = initializer |
(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-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 起) |
带有说明符 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 起)。在这种情况下,选择是在声明一个函数指针类型的参数和声明一个在 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]);
参数类型不能是包含引用或指向未知大小数组的指针的类型,包括此类类型的多级指针/数组,或指向其参数为此类类型的函数的指针。
[编辑] 使用省略号
参数列表中的最后一个参数可以是省略号(...);这声明了一个变参函数。省略号前的逗号可以省略(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-declarator 是一个独立的声明,给定 noptr-declarator 中的 qualified-id 或 unqualified-id 的类型为“derived-declarator-type-list T
”
|
(C++17 起) |
- (在 C++17 之前)(C++17 前)否则,函数的(C++17 起)类型为
“derived-declarator-type-list function of
parameter-type-list cv (可选) ref (可选)(C++11 起) returningT
”。
在语法 (2) 中,假设 noptr-declarator 是一个独立的声明,给定 noptr-declarator 中的 qualified-id 或 unqualified-id 的类型为“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 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 起) | |||||||
属性 | - | (C++11 起) 属性列表。这些属性与 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 | - | 成员初始化列表,仅允许在构造函数中使用 |
复合语句 | - | 由一对花括号包围的语句序列,构成函数的主体 |
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 限定符的)不完整类类型,除非该函数定义为已删除(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 起),则该函数被定义为显式删除。 任何使用已删除函数的行为都是非良构的(程序将无法编译)。这包括调用(显式调用运算符和隐式调用已删除的重载运算符、特殊成员函数、分配函数等)、构造指向已删除函数的指针或成员指针,甚至是在非潜在求值的表达式中使用已删除函数。 非纯虚成员函数可以定义为已删除,即使它被隐式 odr-used。已删除函数只能被已删除函数覆盖,非已删除函数只能被非已删除函数覆盖。
如果函数被重载,则首先进行重载决议,并且只有在选择了已删除函数时,程序才非良构。 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” 函数的已删除定义必须是翻译单元中的第一个声明:先前声明的函数不能被重新声明为已删除。 struct T { T(); }; T::T() = 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; 歧义解决当函数体与以
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 由相同顺序的相同函数契约说明符组成,则它们是相同的。 如果满足以下所有条件,函数声明
如果此条件仅由于比较 predicate 中包含的两个 lambda 表达式而未满足,则无需诊断。 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++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
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-use 是非良构的 已删除虚函数的隐式odr-use是格式错误的 |
此类 odr-use 免于使用禁止 此类odr-use不受禁止 |
CWG 2044 | C++14 | 返回 void 的函数的返回类型推导 如果声明的返回类型是 decltype(auto),则会失败 |
更新推导 规则以处理这种情况 |
CWG 2081 | C++14 | 函数重声明可以使用返回类型 推导,即使初始声明没有 |
不允许 |
CWG 2144 | C++11 | {} 可以在同一位置是函数体或初始化器 | 通过声明符标识符的类型来区分 通过声明符标识符的类型区分 |
CWG 2145 | C++98 | 函数定义中的 declarator 不能加括号 | 允许 |
CWG 2259 | C++11 | 关于带括号的类型名称的歧义解决规则 不包括 lambda 表达式 |
已涵盖 |
CWG 2430 | C++98 | 在类定义中定义成员函数时, 由于 CWG 问题 1824 的解决,该类的类型不能是返回类型或 参数类型 |
仅在 函数体 |
CWG 2760 | C++98 | 构造函数体不包括构造函数常规函数体中未指定的初始化 不包括在构造函数的常规函数体中 |
也包括这些 初始化 |
CWG 2831 | C++20 | 带有 requires-clause 的函数定义 可以定义非模板函数 |
已禁止 |
CWG 2846 | C++23 | 显式对象成员函数不能有类外定义 | 允许 |
CWG 2915 | C++23 | 未命名的显式对象参数可以有 void 类型 | 已禁止 |
[编辑] 参见
C 文档 关于 声明函数
|