What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:programming:cpp:courses:cpp_basic_deep:chpt_6 [2024/10/04 12:53] – [argument dependent lookup] codingharecs:programming:cpp:courses:cpp_basic_deep:chpt_6 [2024/10/05 03:17] (当前版本) – [函数指针作为返回值] codinghare
行 477: 行 477:
  
 ====其他内容==== ====其他内容====
 +==递归函数==
 +  * 通常用于描述复杂的迭代过程
 +===内联函数===
 +  * 普通函数会有额外的开销
 +    * 运行期会建立 stack frame 用于保护函数的掉用
 +  * 内联函数是一种优化机制:如果函数的内部逻辑较为简单,则将函数的内容直接在 ''main'' 中执行
 +  * 编译器替换的机制:
 +    * 取决于编译器的实现机制
 +    * 对于逻辑复杂的函数,overhead 的 cost 不是很明显
 +  * 展开不是简单的替换
 +    * 替换需要保证替换前和替换后执行效果是一样的,需要检测很多问题(比如命名冲突)
 +  * 定义在翻译单元外的函数无法内联:内联发生在编译期,而翻译单元以外的定义处理在链接期
 +==内联函数可以放到头文件中==
 +  * ''inline'' 关键字修饰的函数可以重复定义。
 +  * 实际上,''inline'' 函数保证同时只有一个定义用于链接期。这使得函数定义的范围从翻译单元变为了跨翻译单元。
 +  * ''inline'' 的定义应该与其声明处于同一位置
 +===constexpr 函数===
 +  * ''constexpr'' 函数在编译期和运行期均可执行
 +  * constexpr 函数不能调用 non-constexpr 函数(const 的一致性)
 +<code cpp>
 +// 在编译期和运行期均可调用
 +constexpr int fun(int x ){ return x};
 +// 编译器调用
 +constexpr int x = fun(3);
 +// 运行期调用
 +// 由于参数只能在运行期确定,因此是运行期调用
 +int y;
 +std::cin >> y;
 +fun(y);
 +</code>
 +===consteval 函数===
 +  * C++20 的新内容
 +  * 该函数只能在编译期求值(确保优化)
 +  * 避免在运行期的误调用
 +<WRAP center round box 100%>
 +  * ''inline'' 的出发点是让函数内容在 main 中的调用处展开,因此兼容性最强
 +  * ''constexpr'' / ''consteval'' 更强调在编译期计算
 +</WRAP>
 +===函数指针===
 +  * 函数类型:返回类型+参数类型,比如:''int(int)''
 +  * 只能为函数引入声明,不能直接定义
 +  * 其他使用场景:''std::function'' 可以接受函数类型的参数
 +==函数类型的定义==
 +<code cpp>
 +u,sing K = int(int);
 +// fun 被声明为 int(int) 类型的函数
 +K fun;
 +// 不能通过赋值的方式给出定义
 +K fun = { return 0; } // error
 +</code>
 +==函数指针==
 +<code cpp>
 +#include <iostream>
 +#include <vector>
 +#include <algorithm>
 +
 +using K = int(int);
 +
 +int inc(int x)
 +{
 +    return x + 1;
 +}
 +
 +// 将指向 inc 的函数指针作为参数
 +// 类型为 K*,也就是 int(*)(int)
 +// 好处:高阶函数逻辑不变,通过调用的函数来实现不同的功能
 +// 实例:泛型算法,很多泛型算法接收函数指针作为参数
 +int twiceInc(K* inc, int x)
 +{
 +    int temp = (*inc)(x);
 +    return temp * 2;
 +}
 +
 +
 +int main(int argc, char const *argv[])
 +{
 +    // 不是函数声明,是指针
 +    // 可接收 int(int) 类型的函数
 +    K* fun = &inc;
 +
 +    // 通过指针调用函数
 +    // 解引用->再调用
 +    std::cout <<(*fun)(100) << std :: endl;
 +    std::cout << twiceInc(fun, 100) << std::endl;
 +
 +    // 泛型算法实例
 +    std::vector<int> a{1,2,3,4,5};
 +    std::transform(a.begin(), a.end(), a.begin(), fun);
 +
 +}
 +</code>
 +==函数的退化==
 +  * 赋值时,函数类型会退化为函数指针类型
 +<code cpp>
 +// fun 是 int(*)(int)
 + auto fun = inc;
 +</code>
 +===函数指针与重载===
 +  * 重载时尽量显式的使用函数类型
 +<code cpp>
 +void fun(int) { std::cout << "single para;\n"; }
 +void fun(int, int) {std::cout << "double para;\n"; }
 +
 +int main(int argc, char const *argv[])
 +{
 +    // 无法通过 auto 来推断 fun 的类型
 +    // fun 在此处包含了两个不同类型的函数
 +    // auto 无法确定选择哪一个 fun
 +    auto x = fun;
 +
 +    // 需要显式的指定类型
 +    using K = void(int);
 +    K* x = fun; //int(int) type
 +    return 0;
 +}
 +</code>
 +===函数指针作为返回值===
 +  * 可以使用函数作为返回值
 +  * 函数无法复制,返回的类型是函数指针
 +<code cpp>
 +int inc(int x) { return x + 1; }
 +int dec(int x) { return x - 1; }
 +
 +auto fun(bool condition, int x)
 +{
 +    // 返回的实际上是函数的指针
 +    return condition ? inc(x) : dec(x);
 +}
 +
 +int main(int argc, char const *argv[])
 +{
 +
 +    std::cout << fun(true,1) << std::endl;
 +    return 0;
 +}
 +</code>