C++ 函数模板

函数模板(Function Template) 是C++中实现泛型编程的核心工具,它允许编写与类型无关的通用代码。通过函数模板,你可以定义一个函数蓝图,编译器会根据实际使用的类型自动生成具体的函数代码。

基本概念

1. 模板定义

cpp

// 定义一个函数模板 template <typename T> // T 是类型参数 T max(T a, T b) { return (a > b) ? a : b; } // 或者使用 class 关键字(和 typename 等价) template <class T> T min(T a, T b) { return (a < b) ? a : b; }

2. 模板使用

cpp

int main() { int i1 = 10, i2 = 20; double d1 = 3.14, d2 = 2.71; char c1 = 'A', c2 = 'B'; // 编译器自动推导类型并生成具体函数 cout << max(i1, i2) << endl; // 生成 max<int>(int, int) cout << max(d1, d2) << endl; // 生成 max<double>(double, double) cout << max(c1, c2) << endl; // 生成 max<char>(char, char) return 0; }

模板参数

1. 类型参数

cpp

// 单个类型参数 template <typename T> void print(T value) { cout << value << endl; } // 多个类型参数 template <typename T1, typename T2> auto add(T1 a, T2 b) -> decltype(a + b) { return a + b; } // 使用 print(42); // T = int print("Hello"); // T = const char* add(3, 4.5); // T1 = int, T2 = double

2. 非类型参数

模板参数也可以是(整数、指针、引用等):

cpp

// 数组大小作为模板参数 template <typename T, int size> class FixedArray { private: T data[size]; public: T& operator[](int index) { return data[index]; } }; // 使用 FixedArray<int, 10> arr; // 创建包含10个int的数组 // 函数模板中的非类型参数 template <typename T, int N> void fillArray(T (&arr)[N], T value) { for (int i = 0; i < N; i++) { arr[i] = value; } }

模板实例化

1. 隐式实例化

编译器根据调用自动推导类型:

cpp

template <typename T> T square(T x) { return x * x; } int main() { square(5); // 实例化为 square<int>(int) square(3.14); // 实例化为 square<double>(double) return 0; }

2. 显式实例化

明确指定模板参数:

cpp

template <typename T> void process(T data) { // ... } int main() { process<int>(42); // 显式指定T为int process<double>(3.14); // 显式指定T为double // 即使可以推导,也可以显式指定 process<string>("hello"); // 显式指定T为string return 0; }

函数模板与重载

1. 模板重载

可以定义多个同名的函数模板:

cpp

// 处理单个参数 template <typename T> void print(T value) { cout << "单个值: " << value << endl; } // 处理两个参数 template <typename T1, typename T2> void print(T1 a, T2 b) { cout << "两个值: " << a << ", " << b << endl; } // 处理数组(特化形式) template <typename T, int N> void print(T (&arr)[N]) { cout << "数组: "; for (int i = 0; i < N; i++) { cout << arr[i] << " "; } cout << endl; }

2. 模板与普通函数重载

当模板函数和普通函数重名时:

cpp

// 普通函数 void print(int value) { cout << "普通函数: " << value << endl; } // 模板函数 template <typename T> void print(T value) { cout << "模板函数: " << value << endl; } int main() { print(10); // 优先调用普通函数(精确匹配) print(3.14); // 调用模板函数(生成print<double>) print('A'); // 调用模板函数(生成print<char>) print<>(10); // 强制调用模板函数(print<int>) return 0; }

模板特化

为特定类型提供特殊实现:

cpp

// 通用模板 template <typename T> bool isEqual(T a, T b) { return a == b; } // 特化:针对char*类型 template <> bool isEqual<char*>(char* a, char* b) { return strcmp(a, b) == 0; } // 特化:针对double类型(处理浮点数精度问题) template <> bool isEqual<double>(double a, double b) { return fabs(a - b) < 1e-6; }

模板参数推导与auto

1. 自动类型推导

cpp

template <typename T> auto getValue(T container) -> decltype(container.front()) { return container.front(); } // C++14及以后可以更简洁 template <typename T> auto getValue(T container) { return container.front(); }

2. 使用auto作为参数(C++20)

cpp

// C++20引入的简写函数模板 auto print(auto value) { // 等价于 template<typename T> void print(T value) cout << value << endl; } auto max(auto a, auto b) { // 可以处理不同类型参数 return (a > b) ? a : b; }

实战示例

示例1:通用交换函数

cpp

template <typename T> void swapValues(T& a, T& b) { T temp = a; a = b; b = temp; } int main() { int x = 10, y = 20; swapValues(x, y); // 交换整数 string s1 = "Hello", s2 = "World"; swapValues(s1, s2); // 交换字符串 return 0; }

示例2:查找数组中的最大值

cpp

template <typename T, int N> T findMax(T (&arr)[N]) { T maxVal = arr[0]; for (int i = 1; i < N; i++) { if (arr[i] > maxVal) { maxVal = arr[i]; } } return maxVal; } int main() { int intArr[] = {1, 5, 3, 9, 2}; cout << findMax(intArr) << endl; // 输出 9 double doubleArr[] = {1.1, 5.5, 3.3, 9.9, 2.2}; cout << findMax(doubleArr) << endl; // 输出 9.9 return 0; }

示例3:通用排序函数

cpp

template <typename T> void bubbleSort(T arr[], int size) { for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - i - 1; j++) { if (arr[j] > arr[j + 1]) { swapValues(arr[j], arr[j + 1]); } } } }

注意事项与最佳实践

1. 模板代码放在头文件中

由于模板是在编译时实例化的,通常需要将模板的完整定义放在头文件中。

2. 类型约束(C++20概念)

cpp

// C++20之前:缺乏类型约束 template <typename T> T add(T a, T b) { return a + b; // 如果T不支持+操作符,会在实例化时报错 } // C++20:使用概念约束 template <typename T> requires std::is_arithmetic_v<T> // 约束T必须是算术类型 T add(T a, T b) { return a + b; }

3. 避免代码膨胀

过多不同类型的实例化可能会导致代码体积增大。

4. 编译时错误信息

模板的错误信息通常比较晦涩,因为错误在实例化时才被发现。

函数模板 vs 函数重载

特性函数模板函数重载
目的编写类型无关的通用代码为不同类型提供不同实现
代码量一份模板代码,多份实例每个重载都需要单独实现
类型检查实例化时检查定义时检查
适用场景算法相同,仅类型不同不同类型需要不同处理逻辑

总结

  • 函数模板是实现泛型编程的基础
  • 通过template <typename T>声明模板参数
  • 编译器在编译时根据实际类型生成具体代码
  • 支持类型参数非类型参数
  • 可以与函数重载结合使用
  • 提供模板特化机制处理特殊类型
  • C++20引入了更简洁的auto参数概念约束

函数模板极大地提高了代码的复用性,是STL(标准模板库)的基石,使得编写类型安全且高效的通用算法成为可能。

Read more

手把手实现 STL Set/Map:从零编写一棵红黑树到完整容器封装

手把手实现 STL Set/Map:从零编写一棵红黑树到完整容器封装

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 架构与实现:总览设计框架,深入源码细节 * 二. 核心设计思路:红黑树的泛型复用 * 2.1 红黑树的模板参数设计 * 2.2 仿函数 KeyOfT:统一 key 提取逻辑 * 2.3 核心约束:key 不可修改 * 三. 基础组件实现:红黑树与仿函数 * 3.1 红黑树节点结构 * 3.2 仿函数实现(map/set 层) * 3.2.1

By Ne0inhk
Re:从零开始的 C++ STL篇(七)二叉搜索树增删查操作系统讲解(含代码)+key/key-value场景联合分析

Re:从零开始的 C++ STL篇(七)二叉搜索树增删查操作系统讲解(含代码)+key/key-value场景联合分析

◆ 博主名称: 晓此方-ZEEKLOG博客大家好,欢迎来到晓此方的博客。⭐️C++系列个人专栏: 主题曲:C++程序设计⭐️ 踏破千山志未空,拨开云雾见晴虹。 人生何必叹萧瑟,心在凌霄第一峰 0.1概要&序論 这里是「此方」,好久不见。 今天我们要学习的是二叉搜索树。它是在普通二叉树的基础上加入特定约束,从而具备了高效的搜索能力。虽然这种结构能够支持高效的插入、删除与查找操作,但其性能背后也隐藏着潜在的 效率风险 。同时,在 key 与 key-value 两种不同的应用场景 下,二叉搜索树的设计与实现方式也会产生不同的变化。这里是「此方」。让我们现在开始吧! 前情提要,没有系统学习过一般二叉树的小伙伴直接看这篇文章可能会有些吃力,此方在这里留一个传送门:Re:从零开始的链式二叉树:建树、遍历、计数、查找、判全、销毁全链路实现与底层剖析 一,二叉搜索树的概念

By Ne0inhk
Qt Creator 18.0.2 (macOS, Linux, Windows) - Qt、QML 与 C++ 的 跨平台 IDE

Qt Creator 18.0.2 (macOS, Linux, Windows) - Qt、QML 与 C++ 的 跨平台 IDE

Qt Creator 18.0.2 (macOS, Linux, Windows) - Qt、QML 与 C++ 的 跨平台 IDE cross-platform, integrated development environment (IDE) for application developers to create applications for multiple desktop, embedded, and mobile device platforms. 请访问原文链接:https://sysin.org/blog/qt-creator/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org Qt Creator IDE:

By Ne0inhk