I've got a problem with passing templates (I think that's the cause) from the CLI project.
I've got 3 layers of classes (for encapsulation reasons and technical reasons).
I'll show an example of the buggy part (please no comments about the encapsulation reasons, they're not demonstrated here)
Class A is in a C++ DLL :
class A {
public:
template<class T>
void foo(T blah) { //Do stuff }
}
Class B wraps class A (also regular non-ref class):
class B {
public:
template<class T>
void foo(T blah) { a->foo(blah); }
private:
A* a;
}
Class C is a ref class, which calls class B with an explicit type :
ref class C {
public:
void foo(int blah) { b->foo(blah); }
private:
B* b;
}
They compile alright (.obj is created), but the linker doesn't link the objects correctly.
I get 2 linker errors for the method:
error LNK2028: unresolved token
(0A000645) "public: void __cdecl
B::foo(class utils::CustomString const
&,int const &)"
(??$foo#_N#B#Namespace##$$FQEAAXAEBVCustomString#utils##AEB_N#Z)
referenced in function "private: void
__clrcall C::foo(int)" (??$foo#_N#Namespace##$$FAE$AAMXPE$AAVString#System##_N#Z)
error LNK2019: unresolved external
symbol error LNK2019: unresolved
external symbol "public: void __cdecl
B::foo(class int const &)"
??$foo#_N#B#Namespace##$$FQEAAXAEBVCustomString#utils##AEB_N#Z)
referenced in function "private: void
__clrcall C::foo(int)" (??$foo#_N#Namespace##$$FAE$AAMXPE$AAVString#System##_N#Z)
Edit
I don't have the lines with me now (not on same PC) but it says it couldn't link B.foo referenced in C.foo
I'm compiling the ref class with /clr in debug mode /MDd (yes it has to be in debug mode because of other dependencies that are all compiled the same way)
Anyone knows why this is happening ? And more important: how to solve this ?
Edit:
When setting class B (the wrapper) to be compiled with /GL (Whole Program Optimization) I get a different error:
LNK2001:
error LNK2001: unresolved
external symbol "public: bool __cdecl
Interface::B::foo(int &)const "
(??$foo#_J#B#Namespace##$$FQEBA_NAEBVCustomString#123#AEA_J#Z)
The problem is a bug with visual studio's linker.
First of all, you need to set the /GL (Whole Program Optimization) flag so it links the template after compile.
Then you need to use one of these work-arounds:
BUG: LNK2001 on Member Function When Use Nested Class Template
This is standard lossage with C++ templates, they don't have external linkage like .NET generics. You have to put the template function definition in a header file so you can #include it in the source code file that contains the ref class. Just like your code snippet does. It isn't otherwise specific to C++/CLI.
Be sure to wrap the #include with #pragma managed if you compile the rest of the native classes without the /clr option (like you should). Like this:
#pragma managed(push, off)
#include "FileWithTemplateDefinition.h"
#pragma managed(pop)
These linker errors are pointing out that you are missing a definition somewhere (as opposed to a declaration). Not having access to your code makes this difficult for us to determine, especially without having any verbose linker errors.
[EDIT]
This code compiles and links for me just fine in a managed C++ project:
#pragma managed
class A {
public:
template<class T>
void foo(T blah) { int i = 0; }
};
//Class B wraps class A (also regular non-ref class):
class B {
public:
template<class T>
void foo(T blah) { a.foo(blah); }
private:
A a;
};
// Class C is a ref class, which calls class B with an explicit type :
ref class C {
public:
C() { b = new B(); }
~C() { }
!C() { delete b; }
void foo(int blah) { b->foo(blah); }
private:
B* b;
};
Related
I have a struct containing two functions, one of which is a template function that calls the other. For the sake of organization, I'd like to separate these member functions into separate implementation files instead of defining them all in main.cpp. Visual Studio throws an unresolved external symbol error.
header.hpp:
#pragma once
struct Structure {
void function();
template<bool> void templateFunc();
Structure();
};
implementation.cpp:
#include "header.hpp"
void Structure::function() { return; }
main.cpp:
#include "header.hpp"
template<bool N> void Structure::templateFunc() { return function(); }
Structure::Structure() {}
int main() {
Structure object;
object.function(); // no error
object.templateFunc<0>(); // unresolved external symbol
}
LNK2019: unresolved external symbol 'public: void __cdecl Structure::function(void)' referenced in function 'public: void __cdecl Structure::templateFunc<0>(void)'
When I define the function in main, it compiles and runs.
main.cpp:
#include "header.hpp"
void Structure::function() { return; } // defined in main
template<bool N> void Structure::templateFunc() { return function(); }
Structure::Structure() {}
int main() {
Structure object;
object.function(); // no error
object.templateFunc<0>(); // no error
}
I was initially under the suspicion that my compiler was excluding implementation.cpp, but it fails to compile when syntax errors are present. Oddly, I don't receive a multiple declaration error when the function is defined in both files. I tried reprogramming this from scratch on another device and encountered the same error. I've ensured everything is explicitly included in compilation.
The code I'm hoping for is functionally identical to the code I've found works, but this example represents a larger project I'd like to organize.
Why is this happening? How can I define this function in a separate file?
I'm getting a linking error when calling a template function, but the linker error does not seem to point to the template function. It seems to point to the shared pointer in the function. My class with the template function:
class Blackboard {
public:
template<class T>
bool setValue(std::string key, T* value) {
std::shared_ptr<T> ptr(T);
boost::any v = ptr;
auto it = map.insert(std::pair<std::string, boost::any>(key, v));
return it.second;
}
}
Most similar questions say put all implementation in the header, which I have done. The linking error happens in the class that calls this function. Example class that calls blackboard:
class Example {
void foo(Blackboard* blackboard) {
int* i = new int;
*i = 0;
blackboard->setValue<int>("some key", i);
}
}
The error:
Error LNK2019 unresolved external symbol "class std::shared_ptr<int> __cdecl ptr(int)" (?ptr##YA?AV?$shared_ptr#H#std##H#Z) referenced in function "public: bool __cdecl BehaviorTree::Blackboard::setValue<int>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int *)" (??$setValue#H#Blackboard#BehaviorTree##QEAA_NV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##PEAH#Z)
Both the Blackboard class and the Example class are part of a visual studio static lib project. The linking error occurs when compiling a program using the static library.
I'm having difficulty finding a solution to this problem, so any help would be appreciated!
The problem seems to be that you wrote
std::shared_ptr<T> ptr(T);
instead of
std::shared_ptr<T> ptr(value);
I've got code like this:
#pragma once
#include "MV/stateSystem/StateSystem.hpp"
#include "MV/config/Config.hpp"
namespace mv
{
class Initializator
{
/* ===Objects=== */
public:
protected:
private:
static Initializator *instance;
/* ===Methods=== */
public:
//Inits the program
void init();
static Initializator& getInstance();
static void createInstance();
protected:
private:
Initializator();
Initializator(Initializator const& copy) = delete; // Not Implemented
Initializator& operator=(Initializator const& copy) = delete; // Not Implemented
};
}
and .cpp
#include "Initializator.hpp"
namespace mv
{
Initializator* Initializator::instance;
void Initializator::init()
{
StateSystem::readStatesFromFile("data/states/states.txt");
}
Initializator & Initializator::getInstance()
{
if (instance == 0)
Logger::Log(constants::error::singleton::SINGLETON_NOT_INITED, Logger::STREAM::BOTH, Logger::TYPE::ERROR);
return *instance;
}
void Initializator::createInstance()
{
if (instance == 0)
instance = new Initializator();
}
}
but my compiler has got problem:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "private: __thiscall mv::Initializator::Initializator(void)" (??0Initializator#mv##AAE#XZ) referenced in function "public: static void __cdecl mv::Initializator::createInstance(void)" (?createInstance#Initializator#mv##SAXXZ)
I can't understand it because i've got other class where code is really similar and compiler hasn't got problem with it. In the past, when i've got this problem, i had to declare static members in .cpp file (for example: Initializator* Initializator::instance; ) but now it doesn't help me.
You are declaring the ctor, but not defining it
You can define it within class declaration with
Initializator() = default;
Or
Initializator(){};
Or also in the cpp with
Initializator::Initializator(){}
As the error message is saying, Initializator::createInstance() is calling the ctor, which has to be defined even if it is private
Declaring your default ctor as private prohibits the creation of an implicilty defined default ctor. Thus, you get the unresolved external symbol linker error.
To get it working, provide a valid ctor definition in your code.
Either in the .cpp file, or in the .hpp file ( by provding an in-class definition or writing ctor() = default forcing the automatic generation of a default constructor by the compiler ).
I'm currently transitioning from C# to c++ and I'm constantly hitting road blocks. I got an event handler system from a tutorial and try to adapt it to my needs, but there is an error which I can't understand:
Event:
#pragma once
class Event
{
protected:
virtual ~Event() {};
};
Event Hander:
#pragma once
#include "Event.h"
#include "TypeInfo.h"
#include "HandlerFunctionBase.h"
#include <map>
#include <typeindex>
class EventHandler
{
public:
void HandleEvent(const Event*);
template < class T, class EventT >
void RegisterEventFunc(T*, void (T::*memFn)(EventT*));
private:
typedef std::map<std::type_index, HandlerFunctionBase* > Handlers;
Handlers _handlers;
};
[...]
#include "EventHandler.h"
template < class T, class EventT >
void EventHandler::RegisterEventFunc(T* obj, void (T::*memFn)(EventT*))
{
_handlers[std::type_index(typeid(EventT))]=
new MemberFunctionHandler< T, EventT >(obj, memFn);
}
void EventHandler::HandleEvent(const Event* event)
{
Handlers::iterator it = _handlers.find(std::type_index(typeid(*event)));
if(it != _handlers.end())
{
it->second->exec(event);
}
}
HandlerFunctionBase:
#pragma once
#include "Event.h"
class HandlerFunctionBase
{
public:
virtual ~HandlerFunctionBase() {};
void exec(const Event* event) {call(event);}
private:
virtual void call(const Event*) = 0;
};
MemberFunctionHandler:
#pragma once
#include "handlerfunctionbase.h"
template < class T, class EventT >
class MemberFunctionHandler : public HandlerFunctionBase
{
public:
typedef void (T::*MemberFunc)(EventT*);
MemberFunctionHandler(T* instance, MemberFunc memFn) : _instance(instance), _function(memFn) {};
void call(const Event* event)
{
(_instance->*_function)(static_cast< EventT* >(event));
}
private:
T* _instance;
MemberFunc _function;
};
LogHandler
(My own class, first try to use the system)
#pragma once
#include "EventHandler.h"
#include "LogEvent.h"
class LogHandler
{
public:
LogHandler(EventHandler*);
~LogHandler(void);
private:
void Handle(LogEvent*);
};
#[...]
#include "LogHandler.h"
LogHandler::LogHandler(EventHandler *handler)
{
//This line causes the error
handler->RegisterEventFunc<LogHandler, LogEvent>(this, &LogHandler::Handle);
}
LogHandler::~LogHandler(void)
{
}
void LogHandler::Handle(LogEvent* e)
{
}
What I'm getting when trying to compile this:
Error 1 error LNK2019: unresolved external symbol "public: void __thiscall EventHandler::RegisterEventFunc(class LogHandler *,void (__thiscall LogHandler::*)(class LogEvent *))" (??$RegisterEventFunc#VLogHandler##VLogEvent###EventHandler##QAEXPAVLogHandler##P81#AEXPAVLogEvent###Z#Z) referenced in function "public: __thiscall LogHandler::LogHandler(class EventHandler *)" (??0LogHandler##QAE#PAVEventHandler###Z) D:\Dropbox\C++\D-Tris\D-Tris\D-Tris\LogHandler.obj D-Tris
How is RegisterEventFunc unresolved? It's clearly implemented !?
The compiler has to know the types used to instantiate the template to actually generate the code. But it also generates code for every translation unit (one .cpp file) independently. It doesn't "ignore the files".
So at the point you have the definition of EventHandler::RegisterEventFunc, it can't know with which parameters it will be instantiated, if it's used (instantiated) outside this translation unit.
In LogHandler, it knows about the template EventHandler::RegisterEventFunc (from header file), but as there's no definition, it simply assumes theres instantiation of RegisterEventFunc<LogHandler, LogEvent> elsewhere and doesn't emit any error.
When it's linked together, the linker finds out that no one actually instantiated RegisterEventFunc<LogHandler, LogEvent> so it can't link it together and emits the error you see.
What you can do about it is either:
1) move the definition of EventHandler::RegisterEventFunc to EventHandler.h. (IMHO, this is the usual solution)
2) Or force explicit instantiation in EventHandler.cpp, like
template
void EventHandler::RegisterEventFunc<LogHandler, LogEvent>
(LogHandler* obj, void (LogHandler::*memFn)(LogEvent*))
This "solution" breaks encapsulation, adds lots of dependencies and would be hell to maintain.
3) Or use exported templates. C++ supports (supported) templates the way you want to use them through the keyword export. It was supported only by Comeau and ICC (none of GCC, CLANG, MSVC ever supported this) and now it's removed from standard (In N3690, in [diff.cpp03.temp] (Annex. C.2.7, on page 1240) the standars says: A valid C++ 2003 declaration containing export is ill-formed in this International
Standard.). Don't even try it, I added it just for sake of completeness.
Some related questions that may be interesting for you:
How do I explicitly instantiate a template function?
Using export keyword with templates
Why can templates only be implemented in the header file? (this actually seems like duplicate....)
EDIT: To your other question: You can't remove const qualifier from a variable by static_cast. Casting constness away is potentially dangerous and should be avoided, but if you absolutely need it, you can do it by const_cast< EventT* >(event).
I'm developing in native C++, using visual studio.
I have one project which contains infrastructures - base classes which I want to derive classes from in other projects in the same solution. Say I have a base class in the infrastructres project:
file base.h:
class Base
{
public:
void Foo();
protected:
void Bar();
};
and in another project, a class derived from A, try to call the method bar:
file derived.h:
class Derived : Base
{
public:
void DoSomething();
};
file derived.cpp:
void Derived::DoSomething()
{
Bar();
}
file main.cpp:
void main()
{
Derive d;
d.Foo(); //OK
d.DoSomething(); // Linker error
}
generates the following linker error:
Error 1 error LNK2001: unresolved external symbol "public: virtual void __thiscall Base::Bar(void)" (?Bar#Base##UAEXXZ) main.obj CplusplusTestProject
What am I doing wrong?
Make sure your Base::Bar() method has its implementation somewhere. You can just add curly bracers after its definition and rebuild your project.
The simplest possible problem is that you are not linking the library generated in the other project into your own executable.
You need a definition of the Bar member. Add a definition of Bar in the class definition or in a separate base.cpp file.