C++ 模板
模板是泛型编程的基础,泛型编程是一种编程风格,允许编写函数、类、算法以及处理不同数据类型的不同代码片段。
模板是创建泛型类或函数的蓝图或公式。迭代器和算法等库容器就是泛型编程的例子,它们都是使用模板概念开发的。
每个容器都有一个单一的定义,例如向量,但我们可以定义许多不同类型的向量,例如,vector
函数模板
函数模板定义了函数的蓝图,使函数能够操作不同的数据类型,而无需重写相同的逻辑。
语法
模板函数定义的一般形式的语法如下所示 -
template <typename identifier> function_declaration;
这里的"template"关键字声明了泛型函数,"typename"关键字指定了参数要使用的类型。
示例
以下是返回两个值中最大值的函数模板示例。
#include <iostream> #include <string> using namespace std; template <typename T> inline T const& Max (T const& a, T const& b) { return a < b ? b:a; } int main () { int i = 39; int j = 20; cout << "Max(i, j): " << Max(i, j) << endl; double f1 = 13.5; double f2 = 20.7; cout << "Max(f1, f2): " << Max(f1, f2) << endl; string s1 = "Hello"; string s2 = "World"; cout << "Max(s1, s2): " << Max(s1, s2) << endl; return 0; }
输出
Max(i, j): 39 Max(f1, f2): 20.7 Max(s1, s2): World
类模板
类似地,类模板也定义了创建可处理任何数据类型的类的蓝图。
语法
template <class type> class class-name { . . . }
此处,type 是占位符类型名称,将在实例化类时指定。您可以使用逗号分隔的列表定义多个泛型数据类型。
示例
以下是定义 Stack<> 类并实现泛型方法来从堆栈中推送和弹出元素的示例 -
#include <iostream> #include <vector> #include <cstdlib> #include <string> #include <stdexcept> using namespace std; template <class T> class Stack { private: vector<T> elems; // 元素 public: void push(T const&); // 推送元素 void pop(); // 弹出元素 T top() const; // 返回顶部元素 bool empty() const { // 如果为空,则返回 true。 return elems.empty(); } }; template <class T> void Stack<T>::push (T const& elem) { // 附加传递元素的副本 elems.push_back(elem); } template <class T> void Stack<T>::pop () { if (elems.empty()) { throw out_of_range("Stack<>::pop(): empty stack"); } // 删除最后一个元素 elems.pop_back(); } template <class T> T Stack<T>::top () const { if (elems.empty()) { throw out_of_range("Stack<>::top(): empty stack"); } // 返回最后一个元素的副本 return elems.back(); } int main() { try { Stack<int> intStack; // 整数堆栈 Stack<string> stringStack; // 字符串堆栈 // 操作 int 堆栈 intStack.push(7); cout << intStack.top() <<endl; // 操作字符串堆栈 stringStack.push("hello"); cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const& ex) { cerr << "Exception: " << ex.what() <<endl; return -1; } }
输出
7 hello Exception: Stack<>::pop(): empty stack
模板参数推导
模板参数推导是一项功能,可以自动推导(理解)传递给函数或类模板的参数的数据类型。编译器无需显式指定模板参数,而是会为您计算出来。
示例
让我们看一个模板参数推导的示例 -
template<typename T> T add(T a, T b) { return a + b; } int main() { // 编译器将 T 推断为 int auto result1 = add(5, 3); // 编译器将 T 推断为 double auto result2 = add(3.14, 2.86); }
在这段代码中,我们没有写 add<int>(5,3) 或 add<double>(3.14, 2.86)。编译器会根据您提供的参数推断其类型。
函数模板参数推导
在 C++ 中,函数模板参数是一项功能,它允许编译器根据传递给函数的参数自动推断模板参数的类型。
示例
这是一个函数模板参数推导的简单示例。
#include <iostream> // 函数模板 template<typename T> void printValue(T value) { std::cout << value << std::endl; } int main() { // 使用示例 printValue(42); // T 为 int printValue("Hello"); // T 为 const char* printValue(3.14159); // T 为 double return 0; }
输出
42 Hello 3.14159
类模板参数推导
C++ 中的类模板参数推导功能使编译器能够在创建对象时根据构造函数参数自动推断类模板的模板参数。
示例
以下是类模板参数推导的基本实现。
#include <iostream> template<typename T> class Holder { public: Holder(T value) : data(value) {} void show() const { std::cout << data << std::endl; } private: T data; }; int main() { Holder h1(42); // T 推导为 int Holder h2(3.14); // T 推导为 double Holder h3("Hello"); // T 推导为 const char* h1.show(); // 输出:42 h2.show(); // 输出:3.14 h3.show(); // 输出:Hello return 0; }
输出
42 3.14 Hello
C++ 模板的优势
- 代码可重用性 − 使用模板,您可以编写适用于所有数据类型的通用代码,从而无需为每种所需类型编写相同的代码。通过减少代码重复,节省了开发时间。
- 减少维护 − 更新模板并查看所有实例的变化。这在修复错误、修复问题以及查看所有实例的优势方面效果更佳。
- 增强性能 − 模板实例化在编译时进行,从而减少运行时错误。编译器会针对特定数据类型优化代码。
- 更好地组织代码 − 由于模板将算法逻辑与数据类型分离,因此有助于创建模块化代码,这在开发场景中非常有利。它有助于减少对代码不同实现的搜索。