【发布时间】:2020-07-08 13:29:55
【问题描述】:
几天来我一直在努力解决这个问题,我阅读了很多关于新 C++20 模块的文档和帖子,其中 this official one、this one 和 this other one on Stackoverflow,但我真的无法解决这个问题。
我正在使用随 Visual Studio Preview 16.6.0 2.0 提供的 MSVC 编译器。我知道它还不是一个稳定的版本,但我想尝试一些新功能来开始学习它们。
基本上我写了一个模块(myModule)和这个模块的两个分区(mySubmodule1和mySubmodule2),我在两个模块实现文件(mySubmodule1Impl.cpp和mySubmodule2Impl.cpp)中实现了它们。
mySubmodule1 依赖于mySubmodule2,反之亦然。以下是出处:
mySubmodule1.ixx
export module myModule:mySubmodule1;
export namespace myNamespace{
class MyClass2;
class MyClass1{
public:
int foo(MyClass2& c);
int x = 9;
};
}
mySubmodule2.ixx
export module myModule:mySubmodule2;
import :mySubmodule1;
export namespace myNamespace{
class MyClass2 {
public:
MyClass2(MyClass1 x);
int x = 14;
MyClass1 c;
};
}
mySubmodule1Impl.cpp
module myModule:mySubmodule1;
import :mySubmodule2;
int myNamespace::MyClass1::foo(myNamespace::MyClass2& c) {
this->x = c.x-14;
return x;
}
mySubmodule2Impl.cpp
module myModule:mySubmodule2;
import :mySubmodule1;
myNamespace::MyClass2::MyClass2(myNamespace::MyClass1 c) {
this->x = c.x + 419;
}
myModule.ixx
export module myModule;
export import :mySubmodule1;
export import :mySubmodule2;
如您所见,我可以在mySubmodule1 中转发声明MyClass2,但我不能在mySubmodule2 中转发声明MyClass1,因为在MyClass2 中我使用了MyClass1 类型的具体对象。
我用这一行编译:cl /EHsc /experimental:module /std:c++latest mySubmodule1.ixx mySubmodule2.ixx myModule.ixx mySubmodule1Impl.cpp mySubmodule2Impl.cpp Source.cpp 其中Source.cpp 只是主要的。
在我使用MyClass2 的行中,我在mySubmodule1Impl.cpp 和mySubmodule2Impl.cpp 中收到了臭名昭著的error C2027: use of undefined type 'myNamespace::MyClass2'。此外,编译器告诉我在mySubmodule1.ixx 中查看MyClass2 的声明,其中有前向声明。
现在,我真的不明白我的错误在哪里。我一遍又一遍地检查,但程序的逻辑对我来说似乎很完美。文件的编译顺序应该在实现之前定义MyClass2!
我尝试使用“旧”.h 和 .cpp 文件而不是模块来编译这个确切的程序,它编译并运行良好。所以我想我错过了关于这些新模块的一些东西。
我查看了first official proposal of modules (paragraph 10.7.5),在第一个中,有一个名为宣布所有权声明的构造,在这种情况下似乎是完美的。基本上,它允许您导入当前模块中另一个模块拥有的实体,但不导入模块本身。但是在later revisions of the proposal 中没有任何迹象。绝对没有。而且在新提案的“变更日志”部分甚至没有被引用。
请不要告诉我循环依赖是不好的。我经常知道它们很糟糕,但并非总是如此。即使您认为它们总是很糟糕,我也不会要求经验法则。我在问为什么我的代码用“旧” .h + .cpp 编译而不是新模块。为什么链接器看不到MyClass2的定义。
编辑 1
这是答案中建议的新设计,但它仍然不起作用。我得到完全相同的错误:
mySubmodule1Impl.cpp
module myModule;
int myNamespace::MyClass1::foo(myNamespace::MyClass2& c) {
this->x = c.x-14;
return x;
}
mySubmodule2Impl.cpp
module myModule;
myNamespace::MyClass2::MyClass2(myNamespace::MyClass1 c) {
this->x = c.x + 419;
}
所有其他文件均未更改。
【问题讨论】:
-
此代码中的一些使用
mySubmodule和一些mySubmodule1。这是什么? -
@T.C.对不起,你是对的,它是一样的。在我的代码中,我使用了 mySubmodule,但我认为在示例中将其命名为 mySubmodule1 会更好,以避免误解。我可能忘记更改一些事件。现在我纠正它们,一切都应该没问题。
-
@T.C.嗯,我没有两个同名的模块分区。顺便说一句,如果我删除循环依赖,它就可以工作,所以我认为问题不在于名称,而在于循环依赖本身。谢谢!
-
请注意,这整个问题与使用分区无关。我不使用分区,并且两个模块中的两个类相互引用,因此 forward declare 彼此存在完全相同的问题。编译任一模块都会抱怨“类不完整”并引用前向声明 - 而不是使用完整的类定义。有时它甚至抱怨类 'namespace::A' 不能转换为 'namespace::A' - 显然在内部有它的两个实例。
标签: c++ visual-c++ c++20 c++-modules