请看我们的 Visual Studio 2019版本16.8预览版3发行说明 了解更多最新功能。
我们已经有一段时间没见面了 上次更新 关于C++模块的一致性。在Visual Studio 2019中,工具集、项目系统和IDE团队一直在努力创建一个一流的C++模块体验。有很多东西要分享,所以让我们马上进入:
有什么新鲜事吗?
-
/std:c++latest
意味着C++模块。 - 专用模块片段 是一种新的API封装形式,用于主要模块接口。
- 包括翻译 允许在不更改现有代码的情况下轻松采用头单元。
- 模块连杆 是一种由后端和链接器强制执行的新型链接。
- 项目体系 启用C++模块场景的更改。
- 智能感知 更新。
/std:c++latest
隐含C++模块
自从MSVC开始实现模块TS以来,工具集总是需要使用 /experimental:module
任何汇编。由于模块合并到C++ 20标准中(我们可以) 正式 现在说C++ 20!编译器一直致力于C++ 20模块的一致性,直到我们可以放心地将模块滚动成这样的时间。 /std:c++latest
. 那是现在!
下面有几个警告C++模块的注意事项 /std:c++latest
:
-
/std:c++latest
现在意味着/permissive-
. 这意味着客户当前依赖于编译器的许可行为与/std:c++latest
必须立即申请/permissive
在命令行上。 注: 有可能/permissive
同时禁用模块的使用。 - 现在模块已经进入了最新的语言模式 一些 由于以下原因代码可能会被破坏
module
和import
正在转换为关键字。我们有 记录了一些常见的场景 . 本文介绍了MSVC的实现module
和import
有更多的情况: P1857R1页 . - 这个
std.*
Visual Studio附带的模块将无法通过/std:c++latest
一个人。标准库模块尚未标准化,因此仍处于试验阶段。要继续使用标准库模块,用户将需要/experimental:module
作为命令行选项的一部分。
专用模块片段
C++ 20向主模块接口添加了一个新的部分,称为私有模块片段, [模块.private.frag] . 私有模块片段允许作者真正隐藏库的细节,而不必创建单独的C++源文件来包含实现细节。设想一个场景,在主模块接口中使用PIMPL模式:
module; #include <memory> export module m; struct Impl; export class S { public: S(); ~S(); void do_stuff(); Impl* get() const { return impl.get(); } private: std::unique_ptr<Impl> impl; }; module :private; // Everything beyond this point is not available to importers of 'm'. struct Impl { void do_stuff() { } }; S::S(): impl{ std::make_unique<Impl>() } { } S::~S() { } void S::do_stuff() { impl->do_stuff(); }
在进口方面:
import m; int main() { S s; s.do_stuff(); // OK. s.get(); // OK: pointer to incomplete type. auto impl = *s.get(); // ill-formed: use of undefined type 'Impl'. }
私有模块分区是一个抽象屏障,它将包含模块的使用者从私有分区权限中定义的任何内容中屏蔽出来,从而有效地启用具有更好的卫生、改进的封装和减少的构建系统管理的单“头”库。
包括翻译
随着 收割台单位 包括翻译, [cpp.包括]/7 使编译器能够翻译 #include
指令进入 import
指令,前提是头名称指定了可导入的头(对于MSVC,头单元通过使用 /headerUnit
). 此开关可通过 C/C++ + >所有选项>附加选项 和添加 /translateInclude
. 在未来的版本中,用户可以选择特定的标题,这些标题应该包含翻译,而不是“全部”或“无”开关。
模块连杆
C++模块需要更多的工具集,而不仅仅是解析(前端)。C++ 20引入了一种新的链接风格,即“模块链接”。 [基本链接]/2.2 . 在模块技术规范(TS)时代开发的模块链接的实现,仅仅使用前端名称损坏的概念证明,已经被证明是不完善的,并且在规模上是低效的。从visualstudio201916.8开始,编译器和链接器一起工作以强制模块链接语义(没有前端名称混乱的解决方法)。新的链接器工作意味着用户可以更自由地使用命名模块编写代码,而不必担心可能的名称冲突问题,同时获得任何其他语言工具都无法提供的更强大的odr保证。
强大的所有权
MSVC工具集还采用了 强大的所有权 用于程序链接的模型。强所有权模型通过允许链接器将导出的实体附加到其拥有的模块上,带来了确定性并避免了链接名称的冲突。此功能允许MSVC排除由于链接不同模块(可能是同一模块的修订版)而导致的未定义行为,这些模块报告同一程序中不同实体的类似声明。
例如,考虑下面的例子,它在形式上是未定义的行为(实际上):
m.ixx
export module m; export int munge(int a, int b) { return a + b; }
n.ixx
export module n; export int munge(int a, int b) { return a - b; }
libM.cpp
也是转发声明的头文件 libm_munge
import m; int libm_munge(int a, int b) { return munge(a, b); }
main.cpp
#include "libM.h" import n; // Note: do not import 'm'. int main() { if (munge(1, 2) != -1) return 1; if (libm_munge(1, 2) != 3) // Note uses Module 'm' version of 'munge'. return 1; }
在实践和一般情况下,人们不会像这样有目的地编写代码,但在实践中,在代码迁移、演化和维护下很难避免。在强大的模块所有权语义之前,这样的程序是不可能的(有两个外部链接名) munge
). 强大的所有权购买了这种新的odr担保。有一篇很棒的论文 “C++模块系统” 它详细说明了强大的所有权背后的基本原理。
项目体系
很可能使用C++模块最重要的部分是建立一个可以满足C++模块构建要求的构建系统,同时为用户提供一个没有陡峭的学习曲线的体验。VC项目系统团队一直与编译器工具集团队紧密合作,带来自动模块和头单元支持的经验,最大限度地减少用户设置它们的工作量。
扩展名为.ixx或.cppm的文件被视为“模块接口”源。但最终它是由 编译 属性:
如果要为.h文件构建头单元,则需要将其项类型更改为“C/C++编译器”,默认情况下,H文件位于“C/C++头”组中,不传递给编译器。默认情况下,用C++扩展文件被认为是“头单元”。
项目构建将自动扫描模块和头单元文件(根据其编译为设置),查找同一项目中的其他模块和头单元依赖项,并以正确的依赖项顺序构建它们。
要引用另一个项目生成的模块或头单元,只需添加对该项目的引用。被引用项目中的所有“公共”模块和标题单元都可以在代码中自动引用。
项目可以通过修改以下属性来控制哪些模块和标头(包括构建为标头单元的模块和标头)被视为“公共”:
这段短视频简要介绍了工作流程。唯一的手工工作是将C++语言标准设置为 /std:c++latest
.
编译器开关检修
许多实验阶段 /module:*
前缀开关已关闭,因此我们已将它们以新名称移动到永久性住宅中:
旧的 | 新建 |
---|---|
/module:interface |
/interface |
/module:internalPartition |
/internalPartition |
/module:reference |
/reference |
/module:search |
/ifcSearchDir |
/module:stdIfcDir |
/stdIfcDir |
/module:output |
/ifcOutput |
/module:ifcOnly |
/ifcOnly |
/module:exportHeader |
/exportHeader |
/module:showResolvedHeader |
/showResolvedHeader |
/module:validateChecksum[-] |
/validateIfcChecksum[-] |
希望使用16.8工具集的构建系统和用户应注意新的更改。
智能感知
Visual C++将不是视觉上没有智能的。在16.8中,我们添加了对在模块中使用IntelliSense的完全支持,包括编写模块接口(.ixx)和从导入的模块和头单元获取IntelliSense。对导入模块的IntelliSense支持在Preview 3中不可用,但我们计划在即将到来的预览中启用它。请继续关注我们的CppCon演示,它将提供智能感知使用!
工具集团队一直努力确保编译器发出的C++模块格式是良好记录的,并在智能感知引擎中稳定使用。MSVC负责构建IFC文件,然后由IDE使用。其他工具使用MSVC IFC格式的能力对于健康的生态系统至关重要,而使用IFC输出的IntelliSense引擎是朝着这个方向迈出的第一步。
结束
我们强烈建议您尝试使用VisualStudio2019模块。16.8预览版3将通过 Visual Studio 2019下载 呼叫!
一如既往,我们欢迎您的反馈。欢迎通过电子邮件发送任何评论 visualcpp@microsoft.com 或通过 推特@visualc . 另外,请随时在Twitter上关注我 @星际克隆 .
如果您在VS 2019中遇到MSVC的其他问题,请通过 报告问题 选项,从安装程序或VisualStudioIDE本身。如需建议或错误报告,请通过 开发命令。