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.

Original source

Related problems