您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

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

时间:2023-12-08 13:18:55  来源:微信公众号  作者:coding日记

一、编译器如何处理模板

1.模板代码的处理

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

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

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

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

2.选择性实例化

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

Grid<int> myIntGrid;

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

Grid<int> myIntGrid;
myIntGrid.at(0, 0) = 10;

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

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

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

template class Grid<int>;

注意:显式模板实例化有助于发现错误,因为它强制编译器编译所有即使未使用的类模板方法。使用显式模板实例化时,不要只尝试使用基本类型(如 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 <vector>;
import <optional>;
export template <typename T> class Grid { ... };

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

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


Tags:C++   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
C++常见避坑指南
C++ 从入门到放弃?本文主要总结了在C++开发或review过程中常见易出错点做了归纳总结,希望借此能增进大家对C++的了解,减少编程出错,提升工作效率,也可以作为C++开发的避坑攻略。...【详细内容】
2024-04-03  Search: C++  点击:(4)  评论:(0)  加入收藏
C++ 之父反驳白宫警告:自诞生第一天起,C++ 的目标就一直是提高安全性
整理 | 郑丽媛上个月,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的 19 页 PDF 报告中,呼吁开发人员停止使用容易出现内存安全漏洞的编程语...【详细内容】
2024-03-25  Search: C++  点击:(4)  评论:(0)  加入收藏
八个 C++ 开源项目,帮助初学者进阶成长
通过参与或阅读开源项目的源代码,你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性,可以帮助你深入理解 C++ 的各种概念和技术。1.ThreadPool一个简单的 C++1...【详细内容】
2024-03-22  Search: C++  点击:(21)  评论:(0)  加入收藏
C++多线程编程:解锁性能与并发的奥秘
今天我们将深入探讨C++中的多线程编程,揭示多线程如何解锁性能潜力,提高程序的并发性能。什么是多线程?在计算机科学中,多线程是指一个进程(程序的执行实例)中的多个线程同时执行...【详细内容】
2024-02-03  Search: C++  点击:(68)  评论:(0)  加入收藏
C++代码优化攻略
今天我们将深入探讨C++性能优化的世界。在当今软件开发的浪潮中,高性能的代码是必不可少的。无论是开发桌面应用、移动应用,还是嵌入式系统,性能都是关键。1. 选择合适的数据结...【详细内容】
2024-01-26  Search: C++  点击:(113)  评论:(0)  加入收藏
C++质数检测器的设计与实现​
质数,作为数学中的一个基本概念,一直以其独特的性质吸引着众多研究者和爱好者。质数是指大于1的自然数中,除了1和它本身以外不再有其他因数的数。在实际应用中,质数检测也扮演着...【详细内容】
2024-01-15  Search: C++  点击:(110)  评论:(0)  加入收藏
指针变量在C/C++中的内存占用
在编程领域,尤其是C和C++这类底层语言中,指针是一个核心概念,它允许程序直接操作内存地址。然而,关于指针本身在内存中占用的空间大小,却常常让初学者感到困惑。本文将深入探讨这...【详细内容】
2024-01-09  Search: C++  点击:(94)  评论:(0)  加入收藏
C++的面向对象编程:深入解析与理解
当我们谈论C++时,面向对象编程(OOP)是一个无法回避的话题。那么,C++的面向对象究竟是什么?为什么它如此重要?本文将从基本概念到实际应用,为您详细解析C++中的面向对象编程。一、面...【详细内容】
2024-01-03  Search: C++  点击:(95)  评论:(0)  加入收藏
有什么好用的C/C++源代码混淆工具?
开始使用ipaguard前言iOS加固保护是直接针对ios ipa二进制文件的保护技术,可以对iOS APP中的可执行文件进行深度混淆、加密。使用任何工具都无法逆向、破解还原源文件。对APP...【详细内容】
2023-12-29  Search: C++  点击:(117)  评论:(0)  加入收藏
C++中new与malloc:内存分配机制深度解析
本文旨在深入探讨C++中new和malloc两种内存分配机制的区别。通过对比它们在内存分配、初始化、错误处理、调用构造函数/析构函数、类型转换和使用便捷性等方面的不同,我们将...【详细内容】
2023-12-27  Search: C++  点击:(126)  评论:(0)  加入收藏
▌简易百科推荐
C++常见避坑指南
C++ 从入门到放弃?本文主要总结了在C++开发或review过程中常见易出错点做了归纳总结,希望借此能增进大家对C++的了解,减少编程出错,提升工作效率,也可以作为C++开发的避坑攻略。...【详细内容】
2024-04-03  腾讯技术工程    Tags:C++   点击:(4)  评论:(0)  加入收藏
C++ 之父反驳白宫警告:自诞生第一天起,C++ 的目标就一直是提高安全性
整理 | 郑丽媛上个月,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的 19 页 PDF 报告中,呼吁开发人员停止使用容易出现内存安全漏洞的编程语...【详细内容】
2024-03-25    CSDN  Tags:C++   点击:(4)  评论:(0)  加入收藏
八个 C++ 开源项目,帮助初学者进阶成长
通过参与或阅读开源项目的源代码,你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性,可以帮助你深入理解 C++ 的各种概念和技术。1.ThreadPool一个简单的 C++1...【详细内容】
2024-03-22  AI让生活更美好  微信公众号  Tags:C++   点击:(21)  评论:(0)  加入收藏
C# 中15个值得收藏的开源项目推荐
在开源的世界里,C# 编程语言也占有一席之地。这些开源项目涵盖了多个领域,从框架、库到工具,它们为C#开发者提供了丰富的资源和工具,帮助他们更高效地开发、测试和部署应用程序...【详细内容】
2024-03-20  程序员编程日记  微信公众号  Tags:C#   点击:(29)  评论:(0)  加入收藏
C#异步编程:Task.Run vs. async-await,掌握基础与高级用法
概述:C#中的异步编程有两主要方式:Task.Run用于在后台线程执行同步操作,而async-await更适用于清晰表达异步流程。基础用法展示了它们的简单应用,高级用法则演示了它们的结合使...【详细内容】
2024-03-09  架构师老卢  今日头条  Tags:C#   点击:(22)  评论:(0)  加入收藏
C++多线程编程:解锁性能与并发的奥秘
今天我们将深入探讨C++中的多线程编程,揭示多线程如何解锁性能潜力,提高程序的并发性能。什么是多线程?在计算机科学中,多线程是指一个进程(程序的执行实例)中的多个线程同时执行...【详细内容】
2024-02-03     AI让生活更美好  Tags:C++   点击:(68)  评论:(0)  加入收藏
C++代码优化攻略
今天我们将深入探讨C++性能优化的世界。在当今软件开发的浪潮中,高性能的代码是必不可少的。无论是开发桌面应用、移动应用,还是嵌入式系统,性能都是关键。1. 选择合适的数据结...【详细内容】
2024-01-26  AI让生活更美好  微信公众号  Tags:C++   点击:(113)  评论:(0)  加入收藏
C# 线程本地存储为什么线程间值不一样
为什么用 ThreadStatic 标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类...【详细内容】
2024-01-26  一线码农聊技术  微信公众号  Tags:C#   点击:(66)  评论:(0)  加入收藏
C++质数检测器的设计与实现​
质数,作为数学中的一个基本概念,一直以其独特的性质吸引着众多研究者和爱好者。质数是指大于1的自然数中,除了1和它本身以外不再有其他因数的数。在实际应用中,质数检测也扮演着...【详细内容】
2024-01-15  鲨鱼编程  微信公众号  Tags:C++   点击:(110)  评论:(0)  加入收藏
C# 登顶!超越Java或非空想
整理丨诺亚出品 | 51CTO技术栈(微信号:blog51cto)近日,TIOBE编程社区公布年度编程语言,此次摘得这一桂冠的是C#。这也是C#在TIOBE二十多年评选历史中首次赢得这一年度大奖。C#虽...【详细内容】
2024-01-15    51CTO  Tags:C#   点击:(112)  评论:(0)  加入收藏
站内最新
站内热门
站内头条