Visual C++ 2015 linker error when forward declaring a struct as class
c++, visual-c++
Solution
I've just been facing the same problem with both VC++ 2010 and VC++ 2017, and after some tests I've found that the problem resides in the symbol name the compiler gives to structs and classes internally.
Here a minimum example consisting in three files:
main.cpp
#include "bar.h"
struct Foo {};
int main() {
Foo foo;
bar(&foo);
return 0;
}
bar.h
class Foo;
void bar(Foo* f);
bar.cpp
#include "bar.h"
void bar(Foo* foo) {}
When the project is compiled the following errors and warnings appear:
warning C4099: 'Foo': type name first seen using 'class' now seen using 'struct'
see declaration of 'Foo'
error LNK2019: unresolved external symbol "void __cdecl bar(struct Foo *)" (?bar@@YAXPAUFoo@@@Z) referenced in function _main
fatal error LNK1120: 1 unresolved externals
Now, I swapped the `struct` and `class` declarations, so `main.cpp` and `bar.h` are now:
main.cpp
#include "bar.h"
class Foo {};
int main() {
Foo foo;
bar(&foo);
return 0;
}
bar.h
struct Foo;
void bar(Foo* f);
As expected, the error still pops up:
error LNK2019: unresolved external symbol "void __cdecl bar(class Foo *)" (?bar@@YAXPAVFoo@@@Z) referenced in function _main
BUT, and this is the interesting part, see that the symbols for the expected function (the one used in `main()`) in each case differ:
?bar@@YAXPAUFoo@@@Z (when the parameter is a `struct`)
?bar@@YAXPAVFoo@@@Z (when the parameter is a `class`)
Conclusion
The compiler gives slightly different names if the type is a struct or a class.
The linker then cannot find the proper definition because it is looking for a different one: `bar.cpp` defines one with the forward declaration, but for the moment it is called in `main.cpp` the actual declaration has taken placed, so a different function name is given in the symbols table.
Update (2023-02-03)
I've just seen that clang is able to report this issue:
error: 'Foo' defined as a struct here but previously declared as a class; this is valid, but may result in linker errors under the Microsoft C++ ABI [-Werror,-Wmismatched-tags]
Problem
I have the following code (more than one file involved)... ``` //--- SomeInterface.h struct SomeInterface { virtual void foo() = 0; virtual ~SomeInterface(){} }; //--- SomeInterfaceUser.h #include <memory> //shared_ptr class SomeInterface; //NOTE: struct SomeInterface... causes linker error to go away... class SomeInterfaceUser { public: explicit SomeInterfaceUser(std::shared_ptr<SomeInterface> s); }; //SomeInterfaceUser.cpp #include "SomeInterfaceUser.h" #include "SomeInterface.h" SomeInterfaceUser::SomeInterfaceUser(std::shared_ptr<SomeInterface> s) { } //SomerInterfaceUserInstantiator.cpp #include "SomeInterfaceUser.h" #include "SomeInterfaceImpl.h" struct SomeInterfaceImpl : SomeInterface { virtual void foo(){} }; void test() { SomeInterfaceUser x{std::make_shared<SomeInterfaceImpl>()}; } ``` Using the Visual C++ compiler, I get a linker error (LNK2019). Using GCC 4.8.4 this is not the case. Changing the forward declaration class SomeInterface to struct SomeInterface makes the linker error go away. I always thought that one should be able to use class/struct interchangeably? The interface of SomeInterfaceUser should not depend on whether SomeInterface is defined as class or struct, not so? Is this a Visual C++ bug. I cannot find anything relating to it. I suspect the fact that the struct is used as template parameter has something to do with it. Your help appreciated.