怎样安装网站模板,免费的企业网站建设,网站字体排版技巧,公司网站建设合同 华律网C模板背后的黑箱操作:编译器
编译器如何处理模板
模板代码的处理
为了理解模板的复杂性#xff0c;你需要了解编译器是如何处理模板代码的。当编译器遇到模板方法定义时#xff0c;它会进行语法检查#xff0c;但实际上不会编译模板。编译器不能编译模板定义#xff0c;…C模板背后的黑箱操作:编译器
编译器如何处理模板
模板代码的处理
为了理解模板的复杂性你需要了解编译器是如何处理模板代码的。当编译器遇到模板方法定义时它会进行语法检查但实际上不会编译模板。编译器不能编译模板定义因为它不知道这些模板将用于哪些类型。编译器不可能为像 x y 这样的代码生成代码而不知道 x 和 y 的类型。
当编译器遇到模板的实例化例如 Gridint它会通过将类模板定义中的每个 T 替换为 int 来为 int 版本的 Grid 模板编写代码。当编译器遇到模板的不同实例化例如 GridSpreadsheetCell它会为 SpreadsheetCell 编写另一个版本的 Grid 类。编译器只是写出了如果没有模板支持你需要为每种元素类型编写单独类时的代码。这里没有魔法模板只是自动化了一个烦人的过程。如果你在程序中没有为任何类型实例化类模板那么类方法定义就永远不会被编译。
这种实例化过程解释了为什么你需要在定义的各个地方使用 GridT 语法。当编译器为特定类型如 int实例化模板时它会将 T 替换为 int使 Gridint 成为该类型。
选择性实例化
对于隐式类模板实例化如以下示例
Gridint myIntGrid;编译器总是为类模板的所有虚拟方法生成代码。然而对于非虚拟方法编译器只为你实际调用的那些非虚拟方法生成代码。例如给定前面的 Grid 类模板假设你在 main() 中写了这样的代码仅此代码
Gridint myIntGrid;
myIntGrid.at(0, 0) 10;编译器仅为 int 版本的 Grid 生成无参数构造函数、析构函数和非 const 的 at() 方法。它不会生成其他方法如拷贝构造函数、赋值运算符或 getHeight()。这被称为选择性实例化。
存在的风险是某些类模板方法中的编译错误可能会被忽略。未使用的类模板方法可能包含语法错误因为这些不会被编译。这使得测试所有代码的语法错误变得困难。
你可以通过使用显式模板实例化来强制编译器为所有方法虚拟和非虚拟生成代码。以下是一个示例
template class Gridint;注意显式模板实例化有助于发现错误因为它强制编译器编译所有即使未使用的类模板方法。使用显式模板实例化时不要只尝试使用基本类型如 int实例化类模板还要尝试使用更复杂的类型如 string。 模板对类型的要求
类型独立的代码编写
当你编写与类型无关的代码时必须对这些类型做出某些假设。例如在 Grid 类模板中你假设元素类型由 T 表示是可销毁的、可拷贝/移动构造的以及可拷贝/移动赋值的。
当编译器尝试用不支持类模板方法所使用的所有操作的类型来实例化模板时代码将无法编译且错误消息通常相当晦涩难懂。
然而即使你想使用的类型不支持类模板的所有方法所需的操作你也可以利用选择性实例化来使用某些方法而不是其他方法。
C20 引入的概念Concepts
C20 引入了概念concepts允许你为模板参数编写编译器可以解释和验证的要求。如果传递给模板实例化的模板参数不满足这些要求编译器可以生成更易读的错误消息。后面将讨论概念。 概念为模板编程增加了额外的类型安全性它通过为模板参数提供一个明确的接口合约来实现。这种方式不仅可以防止类型不匹配的问题还可以改善模板错误消息的可读性从而使模板代码更容易维护和理解。 类模板代码的文件
在类模板中类模板定义和方法定义必须对任何使用它们的源文件可用。有几种机制可以实现这一点
方法定义与类模板定义在同一文件
你可以将方法定义直接放在定义类模板本身的模块接口文件中。当你在另一个源文件中导入这个模块以使用模板时编译器将能够访问它所需的所有代码。这种机制用于之前的 Grid 实现。
方法定义在单独的文件
或者你可以将类模板方法定义放在一个单独的模块接口分区文件中。然后你还需要将类模板定义放在自己的分区中。例如Grid 类模板的主模块接口文件可能如下所示
export module grid;
export import :definition;
export import :implementation;这导入并导出了两个模块分区定义definition和实现implementation。类模板定义在定义分区中定义
export module grid:definition;
import vector;
import optional;
export template typename T class Grid { ... };方法的实现位于实现分区中该分区还需要导入定义分区因为它需要 Grid 类模板定义
export module grid:implementation;
import :definition;
import vector;
...
export template typename T GridT::Grid(size_t width, size_t height): m_width { width }, m_height { height } { ... }