模版基础
需要预先学习: 函数 函数模版 函数模版(function template)是一份"函数蓝图"——你只需要写一次逻辑,编译器就能为不同的类型自动生成对应的函数版本。 基础语法 函数模版的声明以 template <typename T> 开头,其中 T 是一个模版参数(template parameter),代表一个待定的类型。使用时,编译器会根据你传入的实参类型推导出 T 的具体类型。 #include <iostream> template <typename T> T max(T a, T b) { return (a > b) ? a : b; } int main() { std::cout << max(3, 7) << '\n'; // T 推导为 int,输出 7 std::cout << max(3.14, 2.71) << '\n'; // T 推导为 double,输出 3.1...
可变长参数模版
需要预先学习: 模版基础 可变长参数模版 普通模版的参数数量是固定的——template <typename T1, typename T2> 只能接受两个类型。而可变长参数模版(variadic template)打破了这一限制:可以写出接受任意数量、任意类型参数的模版。 这是 C++11 引入的特性,std::tuple、std::make_shared、std::thread 的构造函数等大量标准库组件都是基于它实现的。 基础语法 可变长参数模版的核心是参数包(parameter pack)。用 typename... Args 声明一个类型参数包,用 Args... args 声明一个函数参数包: template <typename... Args> void print(Args... args) { // args 是一个参数包,包含调用时传入的全部实参 } Args 是一个类型参数包(type parameter pack),代表零个或多个类型;args 是一个函数参数包(function parame...
Traits(类型萃取)
需要预先学习: 模版基础 Traits(类型萃取) 写泛型代码时,你迟早会遇到一个问题:模版参数 T 到底是个什么类型? 是指针还是普通对象?是整数还是浮点数?去掉引用之后是什么?这些信息在编译期是存在的,但到了运行期已经"擦除"——if 只能根据值做判断,判断不了类型。 **Traits(类型萃取)**就是解决这个问题的技术:定义一类专门的 traits 类,把"关于类型的信息"编码成类成员——你给它一个类型,它告诉你一个编译期的事实(“是不是指针”),或给出一个关联的类型(“去掉指针后剩下的类型”)。“萃取”(extraction)指的正是从类型中提取这些隐藏信息的过程。 注:typeid 虽然能在运行期给出类型名,但泛型代码需要的是能参与编译期计算的答案——用来开分支、声明变量、约束模版,这些 typeid 都做不到。 用偏特化实现编译期分支 从一个需求出发:写一个泛型函数 reset——如果 T 是指针,就 delete 并置空;否则赋一个默认值。这个判断必须发生在编译期,而普通的 if 做不到:它的两个分支都要...
CRTP(奇异递归模板模式)
需要预先学习: 模版基础 继承 多态 CRTP(奇异递归模板模式) CRTP(Curiously Recurring Template Pattern,奇异递归模板模式)是一种继承写法:派生类把自己作为模版参数传给基类。 template <typename Derived> class Base { // 基类通过模版参数 Derived "知道"派生类是谁 }; class Widget : public Base<Widget> // Widget 把自己传给 Base { }; 这样基类在编译期就知道"谁继承了我",可以直接使用派生类的类型——由此得到一类不依赖 virtual 的多态能力,称为静态多态(static polymorphism,编译期多态)。 最小示例 #include <iostream> template <typename Derived> class Base { public: void inter...


