I just found 2 solutions to this problem.
You don't need a mutual dependency for this problem to occur. Just trying to do forward declarations in module interface units instead of imports to further try to improve compilation times is enough to get you on a goose chase like I just got an hour ago.
So, let's say we have 2 modules:
MyType1.ixx:
export module MyType1;
namespace MyNamespace {
class MyType2;
export class MyType1 {
public:
MyType1(MyType2* MyType2);
private:
MyType2* MyType2Intance{};
};
}
Module1.cpp:
module MyType1;
namespace MyNamespace {
MyType1::MyType1(MyType2* MyType2) {
MyType2Intance = MyType2;
};
}
MyType2.ixx:
export module MyType2;
namespace MyNamespace {
export class MyType2 {
public:
};
}
Then if you try to instantiate MyType1 in Main.ixx module:
export module Main;
import MyType1;
import MyType2;
using namespace MyNamespace;
int main() {
MyType2* MyType2Ptr = nullptr;
MyType1 MyType1(MyType2Ptr);
}
You'll get a Error C2665 'MyNamespace::MyType1::MyType1': no overloaded function could convert all the argument types
. Which is absolutely bizarre, since there's enough information to resolve everything. We don't need imports in neither .ixx nor in the .cpp file of MyType1 module for a simple pointer reference. Even if we actually used MyType2 in MyType1.cpp file, we should only need to import MyType2 in the .cpp file and we shouldn't have to import MyType2 in the MyType1.ixx file.
So, what do you do to fix this annoying illogical error that shouldn't exist in the first place?
One solution is to also export the forward-declared class MyType2 in MyType1.ixx:
export module MyType1;
namespace MyNamespace {
export class MyType2;
export class MyType1 {
public:
MyType1(MyType2* MyType2);
private:
MyType2* MyType2Intance{};
};
}
Another solution is to forward-declare the MyType2 class before the export module MyType1
line:
namespace MyNamespace {
class MyType2;
}
export module MyType1;
namespace MyNamespace {
export class MyType1 {
public:
MyType1(MyType2* MyType2);
private:
MyType2* MyType2Intance{};
};
}
And if you use MyType2 in the module implementation file of MyType2, of course, you'll have to import it properly.
I'd show a running compiling example on godbolt or something, but I don't think there's a way to create multi-file solutions like that there.
Now, why this works, I don't really know as I'm only starting with modules myself. Visual Studio warned me yesterday in the build output log that the #include <Windows.h>
after an export module declaration line export module MyModule;
is probably erroneous(but it compiled the solution just fine) and that I should move my #include <Windows.h>
before that line. I did that, it worked, and so that means that there are multiple sections of the module in the module interface file: before export module MyModule;
line and after at the very least.
Also, why does the first solution with exporting the forward declaration fixes the compilation error? The Main module imports both modules, so it doesn't have problems having all information needed.
I did a few tutorials on modules, like this one by Microsoft: https://learn.microsoft.com/en-us/cpp/cpp/tutorial-named-modules-cpp?view=msvc-170
But I don't think any of them explained this forward declaration buggy quirk, and also how #including headers is different before and after the export module MyModule;
line. Let me know if know why and even better if you have a link to video/article/book where it's explained how all this works and why all of this is happening.