Event handler template: unresolved external - c++

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).

Related

Template ctor mssing

I assume the answer will be simple, but I cannot figure out a solution.
I have a class to be used as an interface in the h-file:
template <typename T>
class MyInterface
{
public:
MyInterface();
};
In the cpp-file it is:
#include "MyInterface.h"
template<typename T>
MyInterface<T>::MyInterface()
{
}
My class using the interface is:
class Test : MyInterface<int>
{
};
When compiling I get the error, the ctor of MyInterace is not declared.
unresolved external symbol "public: __thiscall MyInterface::MyInterface(void)" (??0?$MyInterface#H##QAE#XZ) referenced in function "public: __thiscall Test::Test(void)"
Having the ctor declared in the h-file, it compiles.
Templates are instantiated on the fly. If you want to put the constructor in a cpp file, you must specialize it.
#include "MyInterface.h"
template<>
MyInterface<int>::MyInterface()
{
}
Otherwise, it must be in a header as all template functions are managed inline.
If you'd like to keep code organized, make an inl file, with all the function bodies of your code, and then include it at the bottom of your header.
// MyInterface.h
template <typename T>
class MyInterface
{
public:
MyInterface();
};
#include "MyInterface.inl"
// MyInterface.inl
template<class T>
MyInterface<T>::MyInterface()
{
}

virtual function in template inherited class

I am new to templates and I have searched the web for this error but I don't know how to fix it it.
Already checked Why can templates only be implemented in the header file?
State.h
template <class entityType>
class State
{
public:
State() = default;
virtual void Enter(entityType * owner);
};
EnterMine.h
#include "State.h"
class Miner;
class EnterMine : public State<Miner>
{
public:
EnterMine() = default;
virtual void Enter(Miner *) {
};
};
and Miner.cpp is blank
and the problem appears in main.cpp
#include "EnterMine.h"
int main()
{
EnterMine a;
}
The error I get is a linking error :
LNK2001 unresolved external symbol "public: virtual void __thiscall State::Enter(class Miner *)" (?Enter#?$State#VMiner####UAEXPAVMiner###Z)
(Note: this answer was written for the original question, it has been completely rewritten after that.)
Every function that is declared and used, should be defined somewhere.
It seems that you declare EnterMine::EnterMine() but never define it. If this constructor does nothing, either omit it (it will be implicitly defined by a compiler), or mark it as = default;.
class EnterMine : public State<Miner>
{
public:
EnterMine() = default;
...
};
This also applies to the State::State() constructor.
Even though it's a singleton, you're still calling the constructor. Thus, you will still need to define the constructor.
In fact, you need to define every function you declare in your header.

CLI/C++ link error 2028 and 2019

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;
};

Template Factory Pattern in C++

I am trying to make a factory that will have the type passed in, rather then having it hard coded for types. However, when I attempt to add the type to the factory inside of the types .cpp file, I will get a linker error. For example, he is a linker error I am currently getting.
1>RandomClass.obj : error LNK2019: unresolved external symbol "public: short __thiscall TemplatedFactory::AddType(char const *)" (??$AddType#VRandomClass###TemplatedFactory##QAEFPBD#Z) referenced in function "void _cdecl `dynamic initializer for 'private: static short RandomClass::ID''(void)" (??_E?ID#RandomClass##0FA##YAXXZ)
I tried to make the test case as small as possible, though it does cross five files, they are very small
BaseClass.h : http://codepad.org/MhZMw7t0
#pragma once
class BaseClass{ };
RandomClass.h : http://codepad.org/xoObzP8G
#pragma once
#include "BaseClass.h"
class RandomClass : public BaseClass
{
private:
static short ID;
public:
RandomClass();
virtual ~RandomClass();
};
TemplatedFactory.h : http://codepad.org/qkcTBw24
#pragma once
#include <map>
using std::map;
#include "BaseClass.h"
template<typename Type> BaseClass* createType() { return new Type; }
class TemplatedFactory
{
private:
typedef BaseClass* (*ComponentFactoryFuncPtr)();
typedef map<const char*, ComponentFactoryFuncPtr> map_type;
map_type m_Map;
public:
static TemplatedFactory &GetInstance();
template<typename Type>
short AddType(const char* componentName);
};
RandomClass.cpp : http://codepad.org/ALoF3Ysb
#include "RandomClass.h"
#include "TemplatedFactory.h"
short RandomClass::ID = TemplatedFactory::GetInstance().AddType<RandomClass>("RandomClass");
RandomClass::RandomClass() { }
RandomClass::~RandomClass() { }
TemplatedFactory.cpp : http://codepad.org/iqgNqa6H
#include "TemplatedFactory.h"
TemplatedFactory &TemplatedFactory::GetInstance()
{
static TemplatedFactory instance;
return instance;
}
template<typename Type>
short TemplatedFactory::AddType(const char* componentName)
{
ComponentFactoryFuncPtr function = &createType<Type>;
m_Map.insert(std::make_pair(componentName, function));
return 0;
}
I can remove the the linker error if I move
short RandomClass::ID = TemplatedFactory::GetInstance().AddType<RandomClass>("RandomClass");
from RandomClass.cpp to TemplatedFactory.cpp, however, I would like to have the declaration in RandomClass.cpp. Does anyone know of a way to fix this or perhaps a better design (without the use of external libraries).
Templated functions cannot have their definition and declaration separated from each other without export, which your compiler probably doesn't support. You need to move the TemplateFactory::AddType definition to the header.
You cannot place implementation of class template in cpp-file
See some technique for "cheating" on http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14

C++ inheritance problem

I am trying to implement a leftist tree using heaps as a base class. The following is the contents of heap.h:
template <class T>
class heap {
public:
virtual void init(T*) = 0;
virtual void insert(T*) = 0;
virtual T delete_min() = 0;
};
The following is the contents of leftist.cpp:
#include "heap.h"
template <class T>
class leftist_tree : public heap<T> {
private:
T* root;
public:
void init(T* a) {}
void insert(T* a) {}
T delete_min() {T a; return a;}
};
I am passing another class leftist_node as a parameter to this class using the following definition:
leftist_tree<leftist_node> mytree;
I am getting an LNK 2001 unresolved external symbol error for functions init, insert and delete_min. What am I doing wrong?
Edit:
Okay the example I have given at this point is far too complex. I have tried to reproduce the same error on a smaller scale so that someone can identify the problem more easily. I have created the following sample files.
try.cpp
#include "stdafx.h"
#include "myclass.h"
int _tmain(int argc, _TCHAR* argv[])
{
myclass<int> a;
a.hello(3);
return 0;
}
myclass.h
template <class T>
class myclass {
public:
void hello(T);
};
myclass.cpp
#include "myclass.h"
#include <iostream>
using namespace std;
template <class T>
void myclass<T>::hello(T a){
cout<<a<<endl;
system("pause");
}
I get a similar error message:
1>try.obj : error LNK2001: unresolved external symbol "public: void __thiscall myclass::hello(int)" (?hello#?$myclass#H##QAEXH#Z)
1>c:\users\meher anand\documents\visual studio 2010\Projects\try\Debug\try.exe : fatal error LNK1120: 1 unresolved externals
Can you tell me where I am going wrong right now? Thanks
Template functions are treated a little differently from regular functions. The compiler doesn't actually compile the function until you try to use it. If the only place you try to use it is a .cpp where the body of the function is undefined, it assumes it must be compiled somewhere else and makes a reference for the linker to fill in later.
In your case you defined the body of the functions in leftist.cpp, but you didn't use it there, you used it somewhere else. If you had defined it in the .h file then the definition would have been available everywhere you tried to use it and all would be well. If you had used the functions somewhere in leftist.cpp then the functions would have been created and the linker would have fixed everything up.
The general rule is to define the body of all template functions in the header files.
The template isn't instantiated for the type. The easiest way is to remove the .cpp from being compiled, and include it into the cpp where you use the template.
Another easy answer is to just define the whole template in the .h.
Whenever you see this error
error LNK20XX unresolved external symbol
It means that while linking the linker is unable to find the function definition. In your case it is error
Hope this helps you.
Let me know if you need any more help
PK
The following should work (tested with g++):
// File: heap.hh --------------------------
template <class T>
class heap {
public:a
virtual void init(T*) = 0;
virtual void insert(T*) = 0;
virtual T delete_min() = 0;
};
// File: leftist_tree.hh ------------------
#include "heap.hh"
template <class T>
class leftist_tree : public heap<T> {
private:
T* root;
public:
void init(T* ) {}
void insert(T* ) {}
T delete_min() {T a; return a;}
};
// File: leftist_node.hh ------------------
struct leftist_node {
int value;
};
// File: leftist_main.cpp -----------------
#include "leftist_tree.hh"
#include "leftist_node.hh"
int main() {
leftist_tree< leftist_node > mytree;
}