首页 > 科技 > c++20 modules 从量变到质变

c++20 modules 从量变到质变

今天向大家介绍c++20核心语法modules,从c++11到今天的c++20,这是c++不断推陈出新从量变到质变的过程。在介绍modules之前,我们先来了解include机制。

include机制

c++为了完全兼容c语言,让c语言开发者快速学习c++语言,因此继承了c语言的include机制。include是包含的意思,就是将头文件的所有内容复制过来,#则代表预处理的意思,相关的预处理还有#ifdef、#endif,在此就不做过多的介绍。

c++将代码分为头文件和cpp源文件,头文件主要是申明函数等相关接口,cpp文件则是具体实现。开发者可以将cpp文件编译成lib文件,使用者无需关系其具体的实现,这样能很好的将实现逻辑和接口分离。

什么是编译单元

当一个c或cpp文件在编译时,预处理器首先递归包含头文件,形成一个含有所有必要信息的单个源文件,这个源文件就是一个编译单元。

编译单元和头文件

在同一个编译单元里,重复包含头文件会照成重复定义的问题,例如:一个头文件定义了一个class(不是申明),然后在一个cpp文件中包含两次,编译器就会报“类型重定义”错误。为了解决这一编译错误问题,必须要在头文件里写上#ifndef、#define 和 #endif(新版编译器你可以#pragma once),但大多数人认为这一解决办法并不完美。

编译真的很慢很慢

c++编译慢是公认的,你会发现编译一个工程的时间足够干很多事情,其中有一大部分原因就是include照成的。一个公共的头文件很可能被N个编译单元包含,这N个编译单元都会去编译头文件,尤其是修改这个公共头文件,再编译简直让人欲哭无泪,准确的诠释了“牵一发而动全身”。

可以看出include的机制有一系列问题,这些问题总是不尽人意,曾经有多少人抱怨include机制太烂,又有多少人为此转移阵营而投靠其它语言。面对标准委员会的一次又一次推移,最终module特性冻结在c++20。

modules重磅来袭

C++不适应在大规模程序设计与现代开发中的应用环境,越来越多的模板的使用,已经导致了编译时可伸缩性和程序员生产力的严重障碍。它构建性能低下,与云和分布式构建的集成性差。此外,严重依赖头文件包含(即从编译器的角度复制代码)和宏扼杀了C++开发人员的开发。

为了解决以上系列问题,c++20 modules应运而生!(手动特效:金光闪闪)

其中,WG21官方的n4465.pdf文档对modules的目标描述:

1. componentization;

2. isolation from macros;

3. scalable build;

4. support for modern semantics-aware developer tools.

gcc官方对其描述:

Reduce build times due to not reparsing large header files

Proper interface/implementation isolation

Harder to have ODR violations

mvc、gcc、clang 三大编译器基本已完成c++17的开发工作,目前正在开发c++20核心功能。gcc编译器很早就建立了module分支,可以从gcc官网看到,2017年3月1日 第一个模块可执行文件运行。mvc已经开始试验性的支持module,可以从微软官方c++博客看到,vs2015就开始支持modules了,我相信正式版本将很快与我们见面。

开始modules工作

如果您使用的是Visual Studio 2017 15.3之前的版本,请添加/experimental:module /module:stdIfcDir "$(VCToolsInstallDir_150)ifc\$(PlatformTarget)"到`` 配置属性''-> `` C / C ++''->``命令行''以打开该项目的模块。

(我的版本是vs2017 15.9.7 ,所以我直接跳过上一步)接下来,项目属性页->c/c++->语言->c++语言标准选择“最新草案标准(/std:c++latest)”,启用c++模块(实验性)选择“是”。

修改属性页

//#include 
import std.core;

int main()
{
tstd::vector vec;
tvec.push_back(1);
tvec.push_back(2);
tvec.push_back(3);

tfor (auto it = vec.begin(); it != vec.end(); ++it)
t{
ttprintf("%d\n", *it);
t}
tsystem("pause");
treturn 0;
}

以上是stl的modules示例,微软官方提供的std模块参考如下

  • std.regex 提供标题的内容
  • std.filesystem 提供标题的内容
  • std.memory 提供标题的内容
  • std.threadingprovodes头部的内容,
  • std.core 提供C ++标准库中的所有其他内容

自定义模块

新建Mo.ixx文件(注意后缀名的变化),然后我们需要在main函数前导入MO模块(import MO;)并使用它,需要注意的是只有标记export的才会被导出,否则外部无法调用。我们可以在模块中导入子模块,可以用大括号批量export,也可以更小粒度的控制export。

export module MO;
import std.core;
export
{
tvoid test()
t{
ttprintf("test。。。");
t}

tnamespace SPACE
t{
ttclass File
tt{
ttpublic
tttvoid process();
tt};
tt
t}
}

void test2()
{
tprintf("test2。。。");
}

void SPACE::File::process()
{

}

编译它会生成两个文件,分别是obj和ifc。obj我们并不陌生,那么ifc是个什么东西?其实它是模块的二进制描述文件,无法手动更改,虽然没有了头文件,但是需要一个ifc文件,让编译器知道接口信息,用于和其它TU建立桥梁。可以看到模块直接被当做TU处理,无论你有多少个编译单元import该模块,都不会重复编译,大大提高了编译速度,是不是很酷!

c++20 module 将是一个全新的开始,所带来改变是巨大的,这些改变是不言而喻的,从这一刻开始构建你的大型项目。好吧,我们扔掉include,从modules开始,更快的构建速度,更清爽的代码架构,更小的功能依赖,更好的独立组件,像c#一样高效而优雅的开发。

结束语

modules终于来了!模块对于开发的好处毋庸置疑,我相信这是很多人都有所期待的,那些抱怨include垃圾而转移阵营的同学,是时候回归c++了。

从c++11到c++20,还在用c++98的你,我就问你慌不慌?当下急速发展的互联网时代,不学习就意味着淘汰,希望大家勇于接受新事物!

对此有任何疑问,欢迎大家留言,谢谢!

本文来自投稿,不代表本人立场,如若转载,请注明出处:http://www.souzhinan.com/kj/209816.html