C++模块从另一个模块转发声明实体

我最近一直在尝试使用GCC 11将一个代码库转换为C++20模块。然而,我在以下情况下卡住了。首先,下面是使用Header的方法:

A.H

class B;

class A {
    public:
        void f(B& b);
};

A.cpp

#include "A.h"
#include "B.h"

void A::f(B& b)
{
    // do stuff with b
}

(B.H的内容在这里并不重要)

需要注意的是B的向前声明,并不是每个使用A的人都应该关心B,所以我使用了向前声明来阻止重新编译的发生。对于页眉,这种情况可以完美地工作。

问题出在尝试将此代码转换为模块时。主要问题是实体与声明它们的模块捆绑在一起,因此不可能在A.H中向前声明。我尝试在全局模块中进行正向声明,但编译器仍然抱怨B的定义与其声明位于不同的模块中。我还尝试了第三个模块,它只包含B的转发声明,但这仍然是在两个不同的模块中声明和定义B。因此,我的主要问题是:如何从模块外部转发声明内容?我还会对最终产生相同效果的方法感到满意:当B更改时,不需要重新编译A的用户。

在搜索时,我发现有几个地方谈论类似的情况,但由于某种原因,它们都不起作用。它们不起作用的原因:

  • 有人说有一个带有转发声明的模块。正如我上面所说的,这是行不通的。
  • 有人说要用声明的所有权声明。但是,它们已从最终的C++标准中删除。
  • 有人说要用模块分区。然而,只有当A和B在同一模块中时,这才起作用。A和B不应在同一模块中,因此这不起作用。

编辑:作为对评论的回应,以下是我尝试过的几种方法的详细信息:

尝试1:在A.mpp中转发声明B

A.mpp

export module A;

class B;

export class A {
    public:
        void f(B& b);
};

B.mpp

export module B;

export class B {};

A.cpp

module A;

import B;

void A::f(B& b)
{
    // do stuff with b
}

执行此操作时,GCC与

A.cpp:4:11: error: reference to ‘B’ is ambiguous
    4 | void A::f(B& b)
      |           ^
In module B, imported at A.cpp:2:
B.mpp:3:14: note: candidates are: ‘class B@B’
    3 | export class B {};
      |              ^
In module A, imported at A.cpp:1:
A.mpp:3:7: note:                 ‘class B@A’
    3 | class B;

尝试2:在新模块中转发声明

B_decl.mpp

export module B_decl;

export class B;

A.mpp

export module A;

import B_decl;

export class A {
    public:
        void f(B& b);
};

B.mpp

export module B;

import B_decl;

class B {};

A.mpp

module A;

import B;

void A::f(B& b)
{
    // do stuff with b
}

执行此操作时,GCC与

B.mpp:5:14: error: cannot declare ‘class B@B_decl’ in a different module
    5 | class B {};
      |              ^
In module B_decl, imported at B.mpp:3:
B_decl.mpp:3:14: note: declared here
    3 | export class B;

尝试3:在头中转发声明,在模块中定义

B_decl.h

class B;

A.mpp

module;

#include "B_decl.h"

export module A;

export class A {
    public:
        void f(B& b);
};

B.mpp

module;

#include "B_decl.h"

export module B;

class B {};

A.cpp

module A;

import B;

void A::f(B& b)
{
    // do stuff with b
}

执行此操作时,GCC与

B.mpp:7:7: error: cannot declare ‘class B’ in a different module
    7 | class B {};
      |       ^
In file included from B.mpp:3:
B_decl.h:1:7: note: declared here
    1 | class B;

解决方案

此问题的解决方案取决于您首先要转发声明的原因。

如果您这样做是为了打破循环依赖,那么通常的解决方案是将它们放在同一个模块中。由于这些组件紧密耦合在一起,因此将它们放在同一模块中是有意义的。

如果您这样做是为了加快编译速度,那么最好简单地导入模块并使用类型。进口一个模块几乎没有成本。编译该模块,并且只编译一次。

相关文章