【C++20】vs2019使用modules的实际操作

        

目录

一、什么是modules

二、vs版本要求

三、项目配置

四、标准库模块引入方式

五、兼容旧式写法

六、导出类与变量

七、文件后缀

八、实现与主接口分开

九、模块命名与分区

十、引入模块

十一、模块分区       

十一、模块私有部分

十二、结语


        大家好,我是略游。今天讲一讲我在vs上操作C++20新标准模块(modules)的经验。此文章具有时效性,只代表当前实验结果,也可作为一个基本写法入门,将来的编译器一定会完善得更好。

一、什么是modules

        modules是C++20标准的源码组织方式,以替代#include等传统的源码组织方式。与它相关的基本知识网上有很多文章,废话不多说直接实际操作。

二、vs版本要求

        官方文档说16.10版本以上,更新最新版本即可。使用vs2022也可,不过需要注意的是需要安装以下工具:

        虽然在随后的实验中,我没有成功使用上标准库的模块接口,但这个工具是否必须安装,我暂时懒得测试了,在这里获取工具:

三、项目配置

        首先设置C++语言标准为/std:c++ latest,并且启用标准库模块

         在定义使用最新特性的命令行/await

         在链接器中关闭使用增量链接,同时使用程序数据库,这二者是配套的,如果不关闭增量链接,会与模块编译有冲突,后者不能正常识别修改。

四、标准库模块引入方式

        按照微软文档的说法,如下即可导入标准库模块:

import std.core;
import std.filesystem;
//...

         但实际操作中很困难,会提示一些编译选项冲突。除了/EHsc和/MD选项,还有一些其他的定义冲突,例如_DEBUG宏。

        文档链接如下:

Overview of modules in C++ | Microsoft Docs

五、兼容旧式写法

        要以#include包含旧式头文件,可以如下写:

module;
#include "Head.h"
export module Test;

        这里包含了一个头文件Head.h,然后导出了一个模块叫Test。但是此处有一些局限性,Head.h不能是预编译头,预编译头是msvc的一种加快编译速度的方式,但是这里是不能兼容的。

        在Head.h里面我包含了一大串头文件,这样我们也能使用上标准库。当前这样的写法,缺点是每次修改都需要重新编译所包含的头文件内容。预编译头可以解决这个问题,等完全使用上模块后,也能解决这个问题。现在只是兼容的写法。

//Head.h
#pragma once
#include <array>		//!< 数组
#include <list>			//!< 链表
//more...

         值得一提的是,我在包含windows头文件时,遇到一些报错无法解决,最后只好不直接包含windows头文件了,暂时使用传统方法隐藏起来。

        语法很简明,在“module;”和“export module Test;”之间就是旧式的包含头文件方式。

六、导出类与变量

        前面加export即可导出类与全局变量,如下:

module;
#include "Head.h"
export module Test;

export class Test
{
    //...
};

export Test g_test;

         这里就不用再像以往一样,害怕变量重定义,不能直接放置到头文件。在以前的写法就是这样的:

//--------------Test.h
#include "Head.h"

class Test
{
    //...
};

extern Test g_test;

//--------------Test.cpp
Test g_test;

        另外constexpr常量并不能直接导出,因为它是不变量,在编译期就会替换为数值,并不会真实存在这个变量,只能通过命名空间间接导出。

//-----------failed
export constexpr size_t DEFINE_NUM_GOODS_00 = 16 * 22;

//-----------ok
export
namespace Define
{
	constexpr size_t NUM_GOODS_00 = 16 * 22;
}

七、文件后缀

        C++标准没有规定文件的后缀名必须是什么,但是到目前为止,msvc必须使用.ixx后缀名,否则编译器会报错。

        同时还应该设置文件项类型为C/C++编译器 ,如下图所示:

         为了区分主接口文件,我们可以让实现文件后缀为.cpp,但仍然注意属性页里的项类型也要是C/C++编译器。

        直接右键添加一个模块文件,这样也是正确的:

八、实现与主接口分开

        我们可以直接在主接口文件实现Test::Init成员函数的定义,但也可以分开文件存放。例如以下文件Test.cpp,在兼容旧写法的同时,还需表明自己是Test模块的一部分。

module;
#include "Head.h"
module Test;

void Test::Init()
{
}

        在以前的写法,将函数定义在头文件的严重缺点就是,修改此函数就会导致整个文件被修改,然后所有包含此文件的源码都需要重新编译。而模板函数必须放在头文件,不但编译速度极慢,而且无法规避这个问题。而使用模块后便可以改进这个缺点,同时我们还能保持文件分开以保证代码的整洁性。

九、模块命名与分区

        在一些示例中我们可以看到用点来分隔名字,比如export module Test.A,但实际上Test.A就是一个模块的名字,它是一个整体,并不代表Test模块的A分区(点在这里没有任何意义,只是为了好看)。正规的分区写法如下:

//Test.A是一个独立的模块
export module Test.A;

//A是Test的分区
export module Test:A;

        另外微软推荐文件名命名与模块名相似,假设一个模块叫Test.Point:Draw,那么它的文件名应该是Test.Point-Draw.ixx,实现文件可以叫Test.Point-Draw.cpp。即用-来代替:。

十、引入模块

        很简单,如下写即可:

import Test;

        如果想要“转发”模块,在自己引入X的时候,同时引入自己的地方也会引入X,如下所示:

export module Test;

export import Test.Image;
export import Test.Sprite;
export import Test.Tex;
export import Test.Text;
export import Test.UI;

         当另一个文件引入Test时,就不需要再引入Test.Image等了,只需import Test就会import Test.Image等。注意这里的.只是名字的一部分,而不是模块分区,只是为了好看。

        如果只是Test自己使用,去掉export则不会转发:

export module Test;

import Test.Image;
import Test.Sprite;
import Test.Tex;
import Test.Text;
import Test.UI;

十一、模块分区       

        前面用“.”来分隔名字只是一种权宜手段,它们本质上是单独的模块,其余文件不需要通过Test来导入Test.Image,可以直接导入Test.Image。而分区模块如果主接口没有导出,则其他文件是使用不了的。

        假设有个Test:Struct分区,在Main.cpp想要导入。那么这么写是无效的:

import Test:Struct; //error

         而用.的话,就可以:

import Test.Image; //ok

         所以用分区的区别在于此,并且从定义上来说Test:Image是真正属于Test的。

        要定义一个模块分区,如下:

export module Test:Struct;

export
struct A
{
    //...
};

        在上面的代码,在Test:Struct分区导出了一个类A。在Test主接口文件,同样可以选择import或者export import。这决定了Test:Struct是否对外界可见。

//导出模块Test
export module Test;

//导入Define
import Define;

//导入Test.Image并且使导入Test的自动导入Test.Image
export import Test.Image;

//导入Test.Ui供自己使用
import Test.UI;

//导入分区,但是不导出,也可以前面加export导出
import :Struct;

        注意import模块分区时,则必须省略冒号前面的模块名, 想必编译器也是由此判断的。因为不属于Test的模块会import Test:Struct,然而这是不允许的。而属于Test的模块,是知道自己在Test的,所以可以省略“:”前的Test。

十一、模块私有部分

        在声明module :private之后的内容只对自己文件可见,当然这是对于实现文件模块分区来说的。因为一个类或变量是否导出,取决于前面是否有export关键字。

module :private;

十二、结语

        如果你觉得此文章有帮到你,可以点击收藏,然后点击关注,这可以极大的支持我发更多的文章。

        你还可以加我的QQ群讨论:游戏编程星云阁 170100866

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Dev-C++ 和 Visual Studio 2019 都是用于编写 C++ 程序的开发环境,它们之间有一些不同点。 Dev-C++ 是一个免费的集成开发环境,主要用于 Windows 平台,具有简单易用的界面和丰富的功能,包括代码自动完成、调试器、版本控制等。它使用了 GNU 编译器套件(GCC)作为其默认编译器,可以轻松地编译和运行 C++ 代码。 Visual Studio 2019 是一个功能强大的集成开发环境,适用于 Windows 和其他操作系统。它具有更丰富的功能,如代码分析、自动重构、性能分析、测试工具等。Visual Studio 2019 可以使用 Microsoft 的编译器(MSVC)或者 Clang/LLVM 编译器作为默认编译器,它还支持多种编程语言和平台。 总的来说,如果您是初学者或者只需要编写一些简单的 C++ 程序,那么 Dev-C++ 可能会是一个不错的选择。如果您需要进行更复杂的开发或者在多个平台上开发,那么 Visual Studio 2019 可能更适合您的需求。 ### 回答2: DevC++与VS2019是两种不同的编程环境,都可以用于C++语言的开发。但是两者在使用上有一些区别。 首先,在界面上,DevC++更为简洁,不像VS2019那么复杂。DevC++的菜单栏简单明了,各种选项也比较容易找到,初学者入手比较容易。而VS2019则拥有更加复杂的菜单栏以及更多的工具和选项,更加适合有一定开发经验的程序员使用。 其次,在编译方面,VS2019的编译速度要比DevC++更快。而且VS2019的错误提示比较详细,可以帮助程序员更好地定位代码中的问题。DevC++则可能会出现一些比较模糊的错误提示,有时候需要程序员自己去找错。 此外,DevC++对C++11标准的支持程度较低,而VS2019对C++11标准的支持程度很高。这意味着在使用新的C++语言特性时,VS2019比DevC++更为方便。 最后,对于纯粹的C++语言开发而言,DevC++可能会是一个更好的选择,简洁易用,初学者上手较快。而如果需要进行其他类型的开发,如Windows Forms或WPF等GUI编程,或者其他的开发需要,VS2019是更好的选择,因为它拥有更多的开发工具和代码库。 ### 回答3: DevC++和Visual Studio 2019是两个不同的集成开发环境,它们在功能和使用方面有一些不同。以下是它们主要的差异。 首先,在IDE界面方面,两者都有不同的界面风格和用户体验。Visual Studio 2019界面更加美观,功能更加完善,而DevC++趋向于简单实用。另外,Visual Studio 2019是商业软件,而DevC++是免费的开源软件,使用者可以根据自己的需要来选择适合自己的IDE。 其次,在编程语言支持方面,Visual Studio 2019支持多种编程语言,包括C++, C#, Visual Basic等,还可以通过插件来支持其他编程语言。DevC++则只支持C和C++。 另外,在编程工具方面,使用Visual Studio 2019可以访问微软官方提供的大量编程工具,能够为软件开发提供更加全面的支持。而DevC++则可能需要手动安装和设置编译器和库。 最后,在性能方面,Visual Studio 2019相对于DevC++比较占用系统资源,开发大型工程项目时可能需要更高的电脑配置。DevC++则更加轻巧,对系统资源的占用相对较少。 综上所述,DevC++和Visual Studio 2019都有各自的优势和劣势。选择哪个IDE取决于用户的个人需求,开发语言和工程规模。不过,对于初学者来说,DevC++可能更加适合入门,因为它比较简单易用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值