Consider this program:
MyType1.ixx:
export module MyType1;
namespace MyNamespace {
class MyType2;
export class MyType1 {
public:
MyType1(MyType2* MyType2);
void Print();
private:
MyType2* MyType2Instance{};
};
}
Module1.cpp:
module MyType1;
import <iostream>;
import MyType2;
namespace MyNamespace {
MyType1::MyType1(MyType2* MyType2) {
MyType2->Print();
}
void MyType1::Print() {
std::cout << "Hello MyType1\n";
MyType2Instance->Print();
};
}
MyType2.ixx:
export module MyType2;
import <iostream>;
namespace MyNamespace {
export class MyType2 {
public:
void Print() {
std::cout << "Hello MyType2\n";
}
};
}
Main.cpp:
import MyType1;
import MyType2;
using namespace MyNamespace;
void main() {
MyType2 MyType2{};
MyType1 MyType1(&MyType2);
MyType1.Print();
MyType2.Print();
}
Doing this gets me an error in Visual Studio: Error C2665 'MyNamespace::MyType1::MyType1': no overloaded function could convert all the argument types
.
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{};
};
}
The question is why does this work and how does this work, and why a more brain-friendly and intuitive solution of just forward-declaring the class inside the module doesn't work?
What you're trying to do doesn't really make sense. And the fact that you have decided to name your modules the same as your classes makes it extremely difficult to explain what's going on (please stop doing this; modules should not be single-classes in size. There's no point in making modules that small).
In any case, the principle issue is that, if you put a declaration in a module, the module system thinks that you mean it. By declaring
MyNamespace::MyType2
inside of the moduleMyType1
, that means that the module system thinks that...MyNamespace::MyType2
is part ofMyType1
.Therefore, when it gets around to compiling the
MyType2
module, when it finds a class namedMyNamespace::MyType2
, it believes that this is a different class from the one local to theMyType1
module.Because it is.
Therefore, when your
main
function createsMyNamespace::MyType2
, this is of the type from theMyType2
module (since nobody outside ofMyType1
has access to theMyType1
's non-exported stuff). Since this is a different type from the one used byMyNamespace::MyType1
, the compiler cannot convert pointers to two unrelated type.What you have is that the module
MyType1
has a dependency on the moduleMyType2
. It should importMyType2
in its primary module interface. And since you can't useMyType1
without having aMyType2
, it should probablyexport import
it.Or better yet... don't make these into separate modules. They can be in separate module files, but they should all be part of the same module.