服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++模板背后的黑箱操作:编译器

C++模板背后的黑箱操作:编译器

2023-12-08 13:51coding日记 C/C++

为了理解模板的复杂性,你需要了解编译器是如何处理模板代码的。当编译器遇到模板方法定义时,它会进行语法检查,但实际上不会编译模板。

一、编译器如何处理模板

1.模板代码的处理

为了理解模板的复杂性,你需要了解编译器是如何处理模板代码的。当编译器遇到模板方法定义时,它会进行语法检查,但实际上不会编译模板。编译器不能编译模板定义,因为它不知道这些模板将用于哪些类型。编译器不可能为像 x = y 这样的代码生成代码,而不知道 x 和 y 的类型。

C++模板背后的黑箱操作:编译器

当编译器遇到模板的实例化,例如 Grid,它会通过将类模板定义中的每个 T 替换为 int 来为 int 版本的 Grid 模板编写代码。当编译器遇到模板的不同实例化,例如 Grid,它会为 SpreadsheetCell 编写另一个版本的 Grid 类。编译器只是写出了如果没有模板支持,你需要为每种元素类型编写单独类时的代码。这里没有魔法;模板只是自动化了一个烦人的过程。如果你在程序中没有为任何类型实例化类模板,那么类方法定义就永远不会被编译。

这种实例化过程解释了为什么你需要在定义的各个地方使用 Grid 语法。当编译器为特定类型(如 int)实例化模板时,它会将 T 替换为 int,使 Grid 成为该类型。

2.选择性实例化

对于隐式类模板实例化,如以下示例:

Grid myIntGrid;

编译器总是为类模板的所有虚拟方法生成代码。然而,对于非虚拟方法,编译器只为你实际调用的那些非虚拟方法生成代码。例如,给定前面的 Grid 类模板,假设你在 main() 中写了这样的代码(仅此代码):

Grid myIntGrid;
myIntGrid.at(0, 0) = 10;

编译器仅为 int 版本的 Grid 生成无参数构造函数、析构函数和非 const 的 at() 方法。它不会生成其他方法,如拷贝构造函数、赋值运算符或 getHeight()。这被称为选择性实例化。

存在的风险是,某些类模板方法中的编译错误可能会被忽略。未使用的类模板方法可能包含语法错误,因为这些不会被编译。这使得测试所有代码的语法错误变得困难。

你可以通过使用显式模板实例化来强制编译器为所有方法(虚拟和非虚拟)生成代码。以下是一个示例:

template class Grid;

注意:显式模板实例化有助于发现错误,因为它强制编译器编译所有即使未使用的类模板方法。使用显式模板实例化时,不要只尝试使用基本类型(如 int)实例化类模板,还要尝试使用更复杂的类型(如 string)。

二、模板对类型的要求

1.类型独立的代码编写

当你编写与类型无关的代码时,必须对这些类型做出某些假设。例如,在 Grid 类模板中,你假设元素类型(由 T 表示)是可销毁的、可拷贝/移动构造的,以及可拷贝/移动赋值的。

当编译器尝试用不支持类模板方法所使用的所有操作的类型来实例化模板时,代码将无法编译,且错误消息通常相当晦涩难懂。

然而,即使你想使用的类型不支持类模板的所有方法所需的操作,你也可以利用选择性实例化来使用某些方法而不是其他方法。

2.C++20 引入的概念(Concepts)

C++20 引入了概念(concepts),允许你为模板参数编写编译器可以解释和验证的要求。如果传递给模板实例化的模板参数不满足这些要求,编译器可以生成更易读的错误消息。后面将讨论概念。

概念为模板编程增加了额外的类型安全性,它通过为模板参数提供一个明确的接口合约来实现。这种方式不仅可以防止类型不匹配的问题,还可以改善模板错误消息的可读性,从而使模板代码更容易维护和理解。

三、类模板代码的文件

在类模板中,类模板定义和方法定义必须对任何使用它们的源文件可用。有几种机制可以实现这一点:

1.方法定义与类模板定义在同一文件

你可以将方法定义直接放在定义类模板本身的模块接口文件中。当你在另一个源文件中导入这个模块以使用模板时,编译器将能够访问它所需的所有代码。这种机制用于之前的 Grid 实现。

2.方法定义在单独的文件

或者,你可以将类模板方法定义放在一个单独的模块接口分区文件中。然后,你还需要将类模板定义放在自己的分区中。例如,Grid 类模板的主模块接口文件可能如下所示:

export module grid;
export import :definition;
export import :implementation;

这导入并导出了两个模块分区:定义(definition)和实现(implementation)。类模板定义在定义分区中定义:

export module grid:definition;
import ;
import ;
export template  class Grid { ... };

方法的实现位于实现分区中,该分区还需要导入定义分区,因为它需要 Grid 类模板定义:

export module grid:implementation;
import :definition;
import ;
...
export template  Grid::Grid(size_t width, size_t height)
    : m_width { width }, m_height { height } { ... }

原文地址:https://mp.weixin.qq.com/s?__biz=Mzg2NzY2NTUyMg==&mid=2247484699&idx=1&sn=22035077291ce1960529cf58845b3200

延伸 · 阅读

精彩推荐
  • C/C++C++实现分数计算器

    C++实现分数计算器

    这篇文章主要为大家详细介绍了C++实现分数计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    名名名名8542021-11-16
  • C/C++C++嵌入式内存管理详情

    C++嵌入式内存管理详情

    这篇文章主要介绍了C++嵌入式内存管理,是对上一篇内存的一个补充,主要讲解Linux中的内存;这部分对于一些端侧部署的伙伴来说比较重要,推荐针对不...

    一个热爱学习的深度渣渣7032022-03-10
  • C/C++C++ 实现L2-002 链表去重

    C++ 实现L2-002 链表去重

    这篇文章主要介绍了C++ 实现L2-002 链表去重,本文通过简要的案例,解题思路讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    一只特立独行的猫7692021-11-22
  • C/C++C++中Boost.Chrono时间库的使用方法

    C++中Boost.Chrono时间库的使用方法

    chrono是一个time library, 源于boost,现在已经是C++11标准了,下面这篇文章主要给大家介绍了关于C++中Boost.Chrono时间库的使用方法,文中通过示例代码介绍的非常...

    taozj6692021-05-31
  • C/C++Cocos2d-x学习入门之HelloWorld程序

    Cocos2d-x学习入门之HelloWorld程序

    这篇文章主要介绍了Cocos2d-x学习入门之HelloWorld程序,是学习Cocos2d-x的入门程序,其重要性不言而喻,需要的朋友可以参考下...

    C语言程序设计5962021-01-29
  • C/C++C++重载运算符你真的了解吗

    C++重载运算符你真的了解吗

    这篇文章主要为大家详细介绍了C++重载运算符,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来...

    _Phoebe__11202022-10-31
  • C/C++C语言 从根本上理解指针

    C语言 从根本上理解指针

    C语言这门课程在计算机的基础教学中一直占有比较重要的地位,然而要想突破C语言的学习,对指针的掌握是非常重要的,本文将具体针对指针的基础做详...

    清风自在 流水潺潺3972022-11-11
  • C/C++C++实现单例模式的方法

    C++实现单例模式的方法

    这篇文章主要为大家介绍了C++实现单例模式的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助...

    tarespan4772022-07-19