C++模板元编程学习——模板简介

文章目录

  • C++模板的优势
  • C++模板的主要优势包括:
  • 编写你的第一个模板
  • 函数模板的使用
  • 理解模板术语
            • 模板由一个或多个形参参数化(到目前为止,我们看到的例子都只有一个形参)。这些形参称为模板形参,可以分为3类。
        • 可以通过提供替代实现来特化模板。这些实现可以依赖于模板形参的性质特点。特化的目的是实现优化或减少代码膨胀。特化有以下两种形式。
          • 编译器通过将模板定义中的模板形参替换成实参,从而自模板生成代码的过程称为**模板实例化【template instantiation】** 。模板实例化有以下两种形式。
  • 模板的优缺点
          • 优点:
          • 缺点:

C++模板的优势

c++是一门支持多种编程范式的语言,包括:

  • 过程式编程(Procedural Programming):基于函数和过程的结构化编程。
  • 面向对象编程(OOP):通过类、继承和多态实现模块化与复用。
  • 泛型编程(Generic Programming):借助模板编写类型无关的代码,提高代码复用性和灵活性。
  • 函数式编程(Functional Programming):使用不可变数据和高阶函数,提升代码可测试性和并发能力。
  • 元编程(Metaprogramming):利用编译期计算优化程序,提高运行效率。在这些范式中,模板技术是C++的核心特性,它赋予C++强大的泛型编程能力,使代码适用于多种数据类型,而不需要冗余编写。例如,标准模板库(STL)的容器(如std::vector、std:map)和算法((如std::sort、std::find)均依赖模板实现。

C++模板的主要优势包括:

  • 编译时多态(Compile-time Polymorphism):相比运行时多态(如继承与虚函数),模板允许编译期进行类型推导和优化,从而提高执行效率。
  • 编译时计算(Compile-time Computation):利用模板元编程(TMP),C++能在编译期执行计算,减少运行时开销。例如,std::integral_constant 和std::conditional可用于选择编译期代码路径。
  • 代码复用:模板减少了重复代码,提高了通用性。例如,std:enableif可用于 SFINAE(替换失败非错误),实现条件编译。
    模板的强大使其在现代C++开发中占据重要地位,特别是在高性能计算、游戏开发、底层系统编程等领域。掌握模板不仅能提升代码质量,还能帮助程序员深入理解C++语言的底层机制。

编写你的第一个模板

  • 这是一个比较两个值大小的函数模板
cpp 复制代码
//函数模板
template<typename T>
T max(T const &a, T const &b)
{
	return a > b ? a : b;
}

//类模板
template<typename T>
struct vector
{
	vector();
	void push_back(T const &value);
private:
	T* data;	
}

//变量模板
template<typename T>
constexpr T NewLine = T('\n');
  • T成为类型模板形参,由语法template< typename T >或者template< class T >引入。请记住T是形参,因此它可以有任何名称。【在后续的文章中我们会了解更多关于模板形参的内容】

函数模板的使用

cpp 复制代码
struct foo{};
int main
{
	foo f1,f2;
	max(1,2);									//正确,比较int
	max(1.0,2.0);							//正确,比较double
	max(f1,f2);								//错误,foo没有重载operator>
}
  • 在以上代码片段中,首先传入两个整数来调用max,这是可以的,因为int 类型有operator>。这将生成一个重载int max(int const a, int const b)。之后,传入两个double 来调用max,这也是正确的,因为double类型支持operator>。因此,编译器将生成另一个重载 double max(double const a, double const b)。但是,对max的第三次调用将生成一个编译错误,因为foo类型没有重载operator>。
  • 需要指出,调用max函数的完整语法如下。
    • max< int >(1,2);
    • max< double >(1.0, 2.0);
    • max< foo >(f1,f2);
  • 这里编译器推导出模板形参类型,写出类型反而变得多余。但是,在某些情况下编译器无法进行推导,那你就需要用以上语法明确指定类型。

理解模板术语

到目前为止,我们用的都是通用术语"模板"。其实,上文编写的模板可以用4个不同的术语分别描述。

  • 函数模板(function template)是指模板化的函数。之前看到的max模板就是一个例子。
  • 类模板(class template)是指模板化的类((可以使用关键字class、struct或union 定义)。
  • 变量模板(variable template)是指模板化的变量。
  • 别名模板(alias template)是指模板化的类型别名。
模板由一个或多个形参参数化(到目前为止,我们看到的例子都只有一个形参)。这些形参称为模板形参,可以分为3类。
  • 类型模板形参(type template parameters),如template< typename T>, 形参表示的是使用模板时指定的类型。
  • 非类型模板形参(non-type template parameters),如template< size_t N>或template< auto N>,每个形参必须有结构化类型,包括整型、浮点型(C++20支持)、指针类型、枚举类型、左值引用类型等。
  • 模板模板形参(template template parameters),如template< typename K, typename V, template< typename> typename C>,形参的类型是另一个模板。
可以通过提供替代实现来特化模板。这些实现可以依赖于模板形参的性质特点。特化的目的是实现优化或减少代码膨胀。特化有以下两种形式。
  • 部分特化(partial specialization): 只为部分模板形参提供替代实现。
  • (显示)完全特化[(explicit)full specialization]: 为所有模板形参提供特化实现。
编译器通过将模板定义中的模板形参替换成实参,从而自模板生成代码的过程称为模板实例化【template instantiation】 。模板实例化有以下两种形式。
  • 隐式实例化(implicit instantiation): 编译器由于代码中用到了模板而对其进行实例化。只会为实际使用到的组合或者实参进行实例化。
  • 显式实例化(explicit instantiation): 这种方式要显式地告诉编译器需要实例化哪些模板,即便这些实例化在代码中没有显式使用。这在创建库文件很有用,因为未实例化的模板不会被放入目标文件中。

模板的优缺点

优点:
  • 模板可以帮助我们避免编写重复的代码。
  • 模板有利于创建提供算法和类型的泛型库,如标准C++库(有时被错误地称为STL),这些库可以在许多应用程序中使用,不拘类型。
  • 使用模板可以产生更少且更好的代码。例如使用标准库中的算法可以帮助编写更短小的代码,这些代码往往更易于理解和维护,此外,由于这些算法在开发和测试中投入了大量精力,它们通常会更加健壮。
缺点:
  • 语法被认为很复杂而笨拙,尽管稍加练习就不会真正成为开发和使用模板的障碍。
  • 与模板相关的编译错误常常长且晦涩,很难找出错误的原因。较新版本的C++编译器在简化这类错误方面有所进步,但通常仍然是一个重要的问题。C++20标准中引入的概念(concepts)也被看作一种努力,旨在提供更好的编译错误诊断。它们会增加编译时间,因为模板完全在头文件中实现。每当对模板进行更改时,包含该头文件的所有翻译单元都必须重新编译。
  • 模板库作为一个或多个头文件的集合提供,必须与使用它们的代码一起编译。模板在头文件中实现的另一个缺点是缺乏信息隐藏。整个模板代码都在头文件中可读。库开发者通常会使用诸如detail或details等名空间来包含应放在库内部的代码,它们不应该被使用库的人直接调用。由于未使用的代码不会被编译器实例化,这些代码就可能更难验证。因此,在编写单元测试时,务必确保良好的代码覆盖率。对于库尤其如此。
  • 注:尽管缺点列表看起来更长,但使用模板并非坏事,也不应该被回避。相反,模板是C++语言的一个强大特性。模板并不总是被正确理解,有时也会被误用或滥用。但是,请审慎地使用,模板确实有不可否认的优点。
相关推荐
2301_811232982 小时前
C++中的契约编程
开发语言·c++·算法
2401_829004022 小时前
C++中的访问者模式
开发语言·c++·算法
D_evil__2 小时前
【Effective Modern C++】第三章 转向现代C++:13. 优先选用const_iterator,而非iterator
c++
赵萱婷2 小时前
C++17 nodiscard属性深度解析
开发语言·c++·经验分享
kklovecode2 小时前
C++对C语言的增强
c语言·开发语言·c++
m0_748248652 小时前
C语言向C++过渡
c语言·c++·算法
qq_423233902 小时前
跨语言调用C++接口
开发语言·c++·算法