Lap*_*apo 7 c++ visual-c++ c++20 c++-modules
我一直在敲打我的头在这个问题上几天,我读了很多文件和有关新的C ++ 20个模块。其中职位的这名负责人一个,这一个和#2这等一个,但我真的不解决这个问题.
我使用的是随Visual Studio Preview 16.6.0 2.0一起提供的 MSVC 编译器。我知道它还不是一个稳定的版本,但我想弄乱新功能来开始学习它们。
基本上,我编写了一个模块 ( myModule) 和该模块的 2 个分区 ( mySubmodule1and mySubmodule2),并在两个模块实现文件 ( mySubmodule1Impl.cppand mySubmodule2Impl.cpp) 中实现了它们。
mySubmodule1依赖于mySubmodule2,反之亦然。这是来源:
mySubmodule1.ix
export module myModule:mySubmodule1;
export namespace myNamespace{
class MyClass2;
class MyClass1{
public:
int foo(MyClass2& c);
int x = 9;
};
}
Run Code Online (Sandbox Code Playgroud)
mySubmodule2.ix
export module myModule:mySubmodule2;
import :mySubmodule1;
export namespace myNamespace{
class MyClass2 {
public:
MyClass2(MyClass1 x);
int x = 14;
MyClass1 c;
};
}
Run Code Online (Sandbox Code Playgroud)
mySubmodule1Impl.cpp
module myModule:mySubmodule1;
import :mySubmodule2;
int myNamespace::MyClass1::foo(myNamespace::MyClass2& c) {
this->x = c.x-14;
return x;
}
Run Code Online (Sandbox Code Playgroud)
mySubmodule2Impl.cpp
module myModule:mySubmodule2;
import :mySubmodule1;
myNamespace::MyClass2::MyClass2(myNamespace::MyClass1 c) {
this->x = c.x + 419;
}
Run Code Online (Sandbox Code Playgroud)
我的模块.ixx
export module myModule;
export import :mySubmodule1;
export import :mySubmodule2;
Run Code Online (Sandbox Code Playgroud)
如您所见,我可以转发声明MyClass2in mySubmodule1,但不能转发声明MyClass1in mySubmodule2,因为 inMyClass2我使用了类型为的具体对象MyClass1。
我用这一行编译:cl /EHsc /experimental:module /std:c++latest mySubmodule1.ixx mySubmodule2.ixx myModule.ixx mySubmodule1Impl.cpp mySubmodule2Impl.cpp Source.cppwhere Source.cppis just the main.
我收到臭名昭著的错误 C2027: use of undefined type 'myNamespace::MyClass2' in mySubmodule1Impl.cppand mySubmodule2Impl.cppat the line where I use MyClass2. 此外,该编译器告诉我,看的声明MyClass2在mySubmodule1.ixx那里是向前声明。
现在,我真的不明白我的错误在哪里。我一遍又一遍地检查,但程序的逻辑对我来说似乎很完美。文件的编译顺序应该MyClass2在它用于实现之前定义!
我尝试使用“旧” .h 和 .cpp 文件而不是模块来编译这个确切的程序,它编译并运行良好。所以我想我错过了关于这些新模块的一些东西。
我检查了模块的第一个正式提案(第 10.7.5 段),在第一个提案中,有一个名为声明所有权声明的构造,在这种情况下似乎是完美的。基本上它允许您导入当前模块中另一个模块拥有的实体,但不导入模块本身。但在后来的提案修订中,没有任何迹象。绝对没有。在新提案的“变更日志”部分甚至没有被引用。
请不要告诉我循环依赖是不好的。我知道他们经常是坏的,但并非总是如此。即使你认为他们总是坏的,我也不是在要求一个经验法则。我在问为什么我的代码用“旧” .h + .cpp 编译,而不是用新模块编译。为什么链接器看不到MyClass2.
这是答案中建议的新设计,但它仍然不起作用。我得到完全相同的错误:
mySubmodule1Impl.cpp
module myModule;
int myNamespace::MyClass1::foo(myNamespace::MyClass2& c) {
this->x = c.x-14;
return x;
}
Run Code Online (Sandbox Code Playgroud)
mySubmodule2Impl.cpp
module myModule;
myNamespace::MyClass2::MyClass2(myNamespace::MyClass1 c) {
this->x = c.x + 419;
}
Run Code Online (Sandbox Code Playgroud)
所有其他文件都保持不变。
直接的问题是你不能有一个“接口文件”和一个用于单个模块分区的“实现文件” (就好像它是一个头文件和源文件对)。有接口分区和实现分区,但每个分区都必须有自己的名称,因为每个分区都存在以供导入。当然,模块的目的之一也是允许需要头/源对的单个文件:您通常可以将实现包含在与接口文件相同的文件中,但使用export和/或inline仅与后者一起使用。这确实带来了通常的仅标头的缺点,即导致更频繁的下游重建。
元问题是这里没有循环:您已经通过MyClass2. 这是正确的做法:模块不会改变 C++ 的基本语义,因此此类技术仍然适用且必要。出于通常的组织原因,您仍然可以将类划分为两个文件,但根本不需要将方法定义放在分区中(也不需要在单独的module myModule;实现单元中,它们会自动导入所有接口)。的import :mySubmodule1剩余(在界面隔板mySubmodule2)随后明确的和正确的。
至于声明所有权声明,它们出现在没有模块分区的模块 TS 中,这样的情况无法以其他方式处理(因为您可以对来自另一个分区的实体使用正常的前向声明,但不能另一个模块)。