前言(概要)

C++ 编译器对模板的处理能力可以用来实现编译期的计算、类型检查和类型处理(类型修饰),这类技巧或者实践被人们称为「模板元编程」,我们在本篇文章中着重为大家介绍一些模板元编程在(可能不相关的)各个方面的例子。

编译期计算

对于一些可以在程序编译的时候就进行计算的值,使用模板元编程的技巧可以真的让编译器在编译源代码的时候就去计算这些值从而在程序运行的时候就得以直接使用已经计算好了的值,从而省去了程序在运行时去计算这些编译期常量的开销。

随着 constexpr 关键字的出现以及各个主流编译器对新版本 C++ 标准的支持的落实,编译期计算也变得越来越容易上手,即便是 C++ 新手,也能够轻易的指导编译器,使得编译器在编译期就把程序中一些编译期常量计算出来。

类型检查与类型修饰

这方面是模板元编程技巧的主要应用,包括 STL 提供的许多模板,都是关于这方面的,例如 std::remove_reference, std::move, std::declval, std::remove_cvref 等等。举例来说我们可以通过模板元编程的方法检查一个类型是不是引用类型,给一个引用类型去掉引用让它变为非引用类型,让一个编译器根据对一个重载函数模板的调用(构成一个隐式实例化)出现的实参的类型特别特别的版本进行实例化,判断一个类型的静态、公有成员是否存在,判断一个表达式是否合法等等,都属于类型检查与类型修饰的范畴,都可以使用模板元编程技术来实现。

文章主旨与目标读者

这篇文章的目的是为了给读者开阔视野、带来启发以及提升学习兴趣和学习乐趣,这篇文章的目标读者是 C++ 初学者或者自学者。读者不可将这片文章视为权威,读者如有任何疑问应当自行去查阅 C++ 标准或者检索阅读 cppreference 网站。

免责声明

这篇文章的作者不对这篇文章的正确性负责,不可将下文中的任何代码片段应用在生产环境中否则后果自负。

查看类型

通过尝试显式实例化一个没有定义的模板,查看编译器在错误信息中打印出的类型参数的值,利用这种机制我们可以看到编译器推导出的类型是什么:

template <typename T>
class show_type;  // 没有定义,故意没有定义,只有声明。

如何使用:

show_type<int> ();  // T = int
show_type<std::add_lvalue_reference_t<int>> ();  // T = int &
show_type<std::bool_constant<true>::type> ();  // T = bool

然后在 IDE 中(如 CLion),将鼠标悬浮上去即可查看:

截屏2022-10-26 下午7.57.47.png

CLion 弹出的提示小窗口显示:

Implicit instantiation of undefined template 'show_type<int &>'