Why do I get a linker error?
/*
test.cpp
© Andrey Bushman, 18 Jun 2013
*/
//--------------------------------------------
#include <exception>
#include <iostream>
using namespace std;
//--------------------------------------------
namespace Bushman{
//--------------------------------------------
class MyClass{
public:
MyClass();
};
//--------------------------------------------
MyClass::MyClass(){
void func(); // declaration
func(); // call
}
//--------------------------------------------
void func(){ // definition
cout << "Ping..." << endl;
}
}
//============================================
int main()
try{
namespace B = Bushman;
B::MyClass a;
}
catch(exception& e){
cerr << e.what() << endl;
return 1;
}
catch(...){
cerr << "Unknown exception." << endl;
return 2;
}
Result (by MS Visual Studio 2012):
C:\bs\13>cl test.cpp /EHsc
Microsoft (R) C/C++ Optimizing Compiler
Version 17.00.51106.1 for x64 Copyright (C) Microsoft Corporation. All
rights reserved.
test.cpp
Microsoft (R) Incremental Linker Version 11.00.51106.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe test.obj test.obj : error LNK2019: unresolved external
symbol "void __cdecl func(void)" ( ?func@@YAXXZ) referenced in
function "public: __cdecl Bushman::MyClass::MyClass( void)"
(??0MyClass@Bushman@@QEAA@XZ) test.exe : fatal error LNK1120: 1
unresolved externals
C:\bs\13>
Thank you.
It looks like your compiler is erroneously introducing the name into the global namespace, rather than the innermost enclosing namespace (Bushman) as specified by C++11 3.5/7:
When a block scope declaration of an entity with linkage is not found to refer to some other declaration, then that entity is a member of the innermost enclosing namespace.
The code compiles as expected on GCC: http://ideone.com/PR4KVC
You should be able to work around the bug by declaring the function in the correct namespace before (or instead of) declaring it in the constructor's block scope. However, I don't have access to your compiler to test that.
namespace Bushman{
MyClass::MyClass(){
void func(); // declaration
func(); // call
}
//--------------------------------------------
void func(){ // definition
cout << "Ping..." << endl;
}
}
You declare func() inside the MyClass constructor. This should be the same as the func() you defined in the Bushman namespace; but it appears that your compiler gets that wrong. Generally declaring a function inside another function or inside a constructor is considered bad practice. Instead you should declare functions directly in the scope where you intend them to be. In this case, you need a forward declaration of func() inside the Bushman namespace:
namespace Bushman{
void func(); // declaration
MyClass::MyClass(){
func(); // call
}
//--------------------------------------------
void func(){ // definition
cout << "Ping..." << endl;
}
}
Alternatively, you can split your code into separate .h and .cpp files. In fact, this is ideal. I suggest putting func() in func.cpp with a declaration in func.h. Similarly put the MyClass declaration in myclass.h and the MyClass definitions in myclass.cpp. Now myclass.cpp should `#include "func.h".
Using header files this way gives you fine-tuned control over forward declarations and ensures that everything is defined when it is needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With