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

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

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

//a.js
export let val= 'va';
//.b.js
import { val} from 'a.js';

然后就可以在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 <stdio.h>
#include <stdlib.h>
#include <string>
#include <locale.h>
int main()
{
  printf(funca1());
  printf(funca2());
}

在a.cpp中

export module mymoduletesta;

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

export {
  char* funca1() {
    return "funca11";
  }
  char* funca2() {
    return "funca22";
  }
}

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

在main.cpp

import mymoduletesta;

表示导入了名为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})

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

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

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

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

全局模块

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

#include<stdio.h>
export module mymoduletesta;
export {
  char* funca1() {
    return "funca11";
  }
  char* funca2() {
    return "funca22";
  }
}

编译会产生错误

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

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

module;
#include<stdio.h>
export module mymoduletesta;
export {
  char* funca1() {
    return "funca11";
  }
  char* funca2() {
    return "funca22";
  }
}

第一行的

module;

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

模块的导出

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


export module mymoduletesta;
export class abc
{
public:
  char* m1() {
    return "m1";
  }
  char* m2() {
    return "m2";
  }
};

命名空间也可以

export namespace abc
{
  char* m1() {
    return "m1";
  }
  char* m2() {
    return "m2";
  }
};

一般的变量也可以

export module mymoduletesta;
export int x = 123;

如果想在模块中导出模块,例如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 <stdio.h>
int main()
{  
  printf(funcb());
  printf(funca1());
}

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

使用import导入

import mymoduletesta

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

export import mymoduletesta;

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

模块分区

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

分区语法如下

module testmodule:bm;
module testmodule:am;

导入语法如下

import :bm
import :am

以上语法就是把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 <stdio.h>
int main()
{  
  printf(funca1());
  printf(test());
}

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

import :bm;
export import :am;

导入了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先编译

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值