函数
函数(function)是把一个语句序列(函数体, function body)关联到一个名字和零或更多个函数形参(function parameter)的列表的 C++ 实体。
// 函数名:“isodd” // 形参列表拥有一个形参,具有名字 “n” 和类型 int // 返回类型是 bool bool isodd(int n) { // 函数体开始 return n % 2; } // 函数体结束
调用函数时,例如在函数调用表达式中,以各个实参(argument)(可由调用场所提供,或者默认)来初始化各个形参,然后执行函数体中的语句。如果一个函数的形参列表以 ... 结尾,那么额外的实参可以提供给该函数,这样的函数被称为变参函数。
int main() { for(int arg : {-3, -2, -1, 0, 1, 2, 3}) std::cout << isodd(arg) << ' '; // isodd 被调用 7 次, // 每次从 arg 复制初始化 n }
函数调用表达式中无限定的函数名会以一组额外的规则查找,它被称为“实参依赖查找”(argument-dependent lookup/ADL)。
函数可以是协程。协程可以暂停执行,以在之后恢复执行。 |
(C++20 起) |
函数声明可以在任何作用域中出现,但函数定义只能在命名空间作用域出现,或对于成员和友元函数,可以在类作用域中出现。在类体中声明而不带 friend 说明符的函数是类成员函数。这种函数拥有许多附加性质,细节见成员函数。
函数不是对象:不存在函数的数组,而且函数不能按值传递或被其他函数所返回。可以有指向/到除主函数以外的所有函数 (C++20 前)所有非标准库函数和几个标准库函数 (C++20 起)的指针和引用,它们可以用于这些函数自身无法被使用的地方。因此我们说这些函数“可取址”。
每个函数都具有一个类型,它由函数的返回类型,所有形参的类型(进行数组到指针和函数到指针转换后,见形参列表),函数是否为 noexcept
(C++17 起),以及对于非静态成员函数的 cv 限定性和引用限定性 (C++11 起)构成。函数类型同样拥有语言链接。不存在有 cv 限定的函数类型(不要与如 int f() const; 这样的 cv 限定函数类型,或如 std::string const f(); 这样的返回 cv 限定类型的函数相混淆)。如果有任何 cv 限定符被添加到到函数类型的别名,那么它会被忽略。
可以用 lambda 表达式产生无名函数。 |
(C++11 起) |
同一作用域中,可以有多个函数拥有相同的名称,只要其形参列表,以及对于非静态成员函数的 cv 或引用 (C++11 起)限定不同即可。这被称作函数重载。只有返回类型及 noexcept 说明 (C++17 起)不同的函数声明之间无法重载。重载函数的地址有专门的确定方法。
函数对象
除了函数左值,函数调用表达式还支持函数指针以及重载了函数调用运算符及可转换为函数指针的任何类类型的值(包括 lambda 表达式) (C++11 起)。这些类型被统称为函数对象 (FunctionObject) ,而且在 C++ 标准库中的各处都有使用,示例可见二元谓词 (BinaryPredicate) 和比较 (Compare) 的用法。
标准库也提供数个预定义的函数对象模板,以及一些组成新函数对象的方法(包括 std::less、std::mem_fn、std::bind 和 std::function (C++11 起))。