• 【C++】不用include,使用C++模块语法实现函数调用


    写C++的时候,我们要调用其他文件中的函数或者类这些,一般情况下,就是include一个头文件,或者extern。但在C++20中,有了一个更好的调用方式:使用模块化方式进行调用。

    如果使用过javascrtip的话,对这种语法看上去就比较熟悉,在javascript中

    //a.js
    export let val= 'va';
    //.b.js
    import { val} from 'a.js';
    
    • 1
    • 2
    • 3
    • 4

    然后就可以在b.js中使用val了

    C++使用模块,也差不多,可能比在JS中使用还要简便一点,举例如下

    以下代码在cygwin gcc11.3 cmake3.23.2中测试

    模块基本使用

    //a.cpp
    export module mymoduletesta;
    export {
      char* funca1() {
        return "funca11";
      }
      char* funca2() {
        return "funca22";
      }
    }
    
    //main.cpp
    import mymoduletesta; 
    #include 
    #include 
    #include 
    #include 
    int main()
    {
      printf(funca1());
      printf(funca2());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在a.cpp中

    export module mymoduletesta;
    
    • 1

    表示定义了一个导出模块,模块名为mymoduletesta

    export {
      char* funca1() {
        return "funca11";
      }
      char* funca2() {
        return "funca22";
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    表示导出本模块的两个函数funca1,funca2

    在main.cpp

    import mymoduletesta;
    
    • 1

    表示导入了名为mymoduletesta的模块,然后就可以像以前写include方式那样调用mymoduletesta模块中导出的函数

    我使用了cmake进行编译,cmake的定义如下

    CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
    PROJECT(cx)
    AUX_SOURCE_DIRECTORY(. DIR_SOURCE)
    SET(CMAKE_BUILD_TYPE "Debug")
    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_STANDARD_REQUIRED True)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmodules-ts")
    ADD_EXECUTABLE(app ${DIR_SOURCE})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    主要是这两句重要,没有的话编译会报错。-fmodules-ts表示要使用模块功能

    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmodules-ts")
    
    • 1
    • 2

    另外gcc的版本要在11以上才行

    上面就是c++模块的基本使用方式

    全局模块

    在模块功能中,是不能使用#include语法的,例如上例中,如果改为

    #include
    export module mymoduletesta;
    export {
      char* funca1() {
        return "funca11";
      }
      char* funca2() {
        return "funca22";
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    编译会产生错误

    error: module-declaration only permitted as first declaration, or ending a global module fragment

    但是,如果这个模块作为全局模块处理的话,就可以了

    module;
    #include
    export module mymoduletesta;
    export {
      char* funca1() {
        return "funca11";
      }
      char* funca2() {
        return "funca22";
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    第一行的

    module;
    
    • 1

    表示为这是个全局模块,这种模块是可以使用include引入其他文件

    模块的导出

    事实上,exprot不局限于导出一般函数,类也可以导出

    
    export module mymoduletesta;
    export class abc
    {
    public:
      char* m1() {
        return "m1";
      }
      char* m2() {
        return "m2";
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    命名空间也可以

    export namespace abc
    {
      char* m1() {
        return "m1";
      }
      char* m2() {
        return "m2";
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    一般的变量也可以

    export module mymoduletesta;
    export int x = 123;
    
    • 1
    • 2

    如果想在模块中导出模块,例如main.cpp中要调用a.cpp模块中的一个函数,但是mian.cpp并没有导入a.cpp模块,只导入了b.cpp,但b.cpp中导入了a.cpp模块,代码如下

    //a.cpp
    export module mymoduletesta;
    export {
      char* funca1() {
        return "funca11";
      }
      char* funca2() {
        return "funca22";
      }
    }
    //b.cpp
    export module mymoduletestb;
    import mymoduletesta;
    export char* funcb() {
        return funca1();
    }
    //main.cpp
    import mymoduletestb; 
    #include 
    int main()
    {  
      printf(funcb());
      printf(funca1());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这时候在main.cpp中要调用a.cpp中funca1(),那就不能只在b.cpp模块中仅

    使用import导入

    import mymoduletesta
    
    • 1

    这是不够的,要把上一句改成

    export import mymoduletesta;
    
    • 1

    这样,在b.cpp中也可以调用a.cpp中的函数,在main.cpp虽然没有导入a.cpp的模块,但是在b.cpp中导出了a.cpp模块,所以,在main.cpp中就也可以使用了

    模块分区

    一个模块可以有模块分区单元。分区的意思就是把一个模块分成几个独立的模块,但是使用的时候却和使用一个完整的模块一样

    分区语法如下

    module testmodule:bm;
    module testmodule:am;
    
    • 1
    • 2

    导入语法如下

    import :bm
    import :am
    
    • 1
    • 2

    以上语法就是把testmodule模块,分为bm,am两个模块分区,但是模块分区只能被相同具名模块的模块单元导入

    例如上头两个模块,只能被testmodule模块导入

    举例如下

    //a-a.cpp
    export module mymoduletesta:am;
    export {
      char* funca1() {
        return "funca1";
      }
    }
    //a-b.cpp
    module mymoduletesta:bm;
    char* funca2() {
      return "funca2";
    }
    //a-c.cpp
    export module mymoduletesta;
    import :bm;
    export import :am;
    export char* test()
    {
      return funca2();
    }
    //main.cpp
    import mymoduletesta; 
    #include 
    int main()
    {  
      printf(funca1());
      printf(test());
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在上面实例中,mymoduletesta有两个分区,am,bm,在a-c.cpp中,

    import :bm;
    export import :am;
    
    • 1
    • 2

    导入了bm,am分区,但是因为bm分区中,没有导出模块,所以,在a-c.cpp中,可以导入bm,也可以使用funca2函数,但是在main.cpp中不能使用funca2,但是am中的funca1,和mymoduletesta中的test因为导出,在main.cpp中可以使用

    以上就是C++20中模块的基本使用方式了,还有一点很重要,编译顺序。如果在b.cpp中要使用a.cpp模块,就必须要先让a.cpp先编译

  • 相关阅读:
    Java类部类
    移动开发如何用好热更新?说说其中的技术原理
    vscode快速安装教程
    Matlab:构建模式表达式
    经验之谈:AntD级联选择动态加载数据
    快速掌握Reactor Core实现响应式编程
    【ASE+python学习】批量实现将含有空位的结构进行氢饱和(实际就是在某个位置添加氢原子)
    JUC 笔记 8
    【VSCode设置单个子文件时不要平级显示】
    Kafka消息队列
  • 原文地址:https://blog.csdn.net/weixin_44305576/article/details/126452835