C++中的模板与类型化:从泛型到概念

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C++中的泛型与类型化:为什么不仅仅是“简单的模板”?



当开发者从Python或Java转向C++时,常常会被“模板”(template)这个词吓到。脑海中会浮现出无穷无尽的尖括号、难以理解的编译错误以及std::vector的魔法。实际上,C++中的泛型(或泛型编程)是一个极其强大的工具,它允许你编写一次代码,然后将其用于任何数据类型。而且,这与Java或C#中的泛型完全不同。



在本文中,我们将探讨C++中的类型化如何通过模板工作,类模板与函数模板有何不同,以及为什么在C++20中引入了概念。我们将提供大量示例——从简单到实际可用于生产环境的示例。开始吧!



什么是C++中的泛型(模板)?



简单来说:C++中的模板是一种编写代码的方式,使其能够处理任何数据类型,同时不损失性能。与Python的动态类型化(在运行时检查类型)不同,C++在编译阶段为每个使用的类型生成独立的函数或类版本。这被称为带参数化的静态类型化。



在语法上,模板使用关键字template和尖括号中的参数声明:



template <typename T>T max(T a, T b) {    return (a > b) ? a : b;}


这里的typename T是模板参数。你可以使用class代替typename——没有区别。当你编写max(3, 7)时,编译器会自动将int替换T,并创建函数int max(int, int)。如果你写max(3.14, 2.71),则会得到double版本。简单而高效。



函数模板:迈向泛型的第一步



我们从简单的开始——C++中的函数模板。当逻辑相同但类型不同时,这是避免代码重复的理想方式。



示例:一个将元素打印到控制台的函数(对调试很有用):



#include <iostream>#include <string>

template <typename T>void print(const T& value) { std::cout << value << std::endl;}

int main() { print(42); // int print(3.1415); // double print("Hello"); // const char* print(std::string("Generics!")); // std::string return 0;}


注意:我们使用const T&——这是C++中的类型化,通过常量引用传递,以避免复制大型对象。对于内置类型(int、double)来说这并不关键,但这是一个好习惯。



如果需要传递两个不同类型的参数怎么办?很简单:



template <typename T1, typename T2>auto add(T1 a, T2 b) -> decltype(a + b) {    return a + b;}

// 在C++14及更新版本中,可以简化为:template <typename T1, typename T2>auto add(T1 a, T2 b) { return a + b;}


这里的auto会自动推导返回类型。这就是泛型在行动——一份代码,无限的类型组合。



类模板:构建通用结构



现在我们来讨论C++中的类模板。这是标准库(STL)的基础:std::vector<T>、std::map<Key, Value>、std::optional<T>——所有这些都通过模板实现。



让我们编写一个简单但具有说明性的示例——模板类“Pair”(类似于std::pair):



template <typename First, typename Second>class Pair {private:    First first_;    Second second_;public:                

博客

书籍推荐