Sign in to follow this  

Problems with templates in C++

This topic is 1989 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Okey, help please - can't figure out how to fix this;

Here is Entity.cpp
[source lang="cpp"]#if !defined OP_ENTITY
#define OP_ENTITY

#include "OPEngine.h"

class Entity
{
public:
void initialize();

bool attachComponent(Component* compPtr);

template<class T>
void addAttribute(std::string name);

void handleMessage(Message* msg);

template<class T>
Attribute<T>* getAttribute(std::string name);

template<class T>
T* getAttributeDataPointer(std::string name);


private:

protected:
sf::Vector2f m_Position;
float m_Rotation;
std::map<uint, Component*> m_Components;
std::map<uint, void*> m_Attributes;
uint m_EntityName;

};

#endif[/source]

Here is the cpp file
[source lang="cpp"]#include "Entity.h"

// Public
bool Entity::attachComponent(Component* compPtr)
{
uint hashName = compPtr->getNameHash();
if(this->m_Components.find(hashName) != this->m_Components.end())
{
WARN("Tried to attach component but a component with the same name was already attached");
return false;
}
else
{
std::pair<uint, Component*> componentPair(hashName, compPtr);
this->m_Attributes.insert(componentPair);
LOG("Component successfully attached to entity");
return true;
}
}

template<class T>
void Entity::addAttribute(std::string name)
{
void* ptr = new Attribute<T>();
uint hashname = System::hash(name);
std::pair<std::string, void*> pair(hashname, ptr);
this->m_Attributes.insert(pair);

/*
if(this->m_Attributes.find(hashName) != this->m_Attributes.end())
{
WARN("Tried to register attribute but name was already taken");
return false;
}
else
{
void* attrPtr = new Attribute<T>();
std::pair<uint, void*> attributePair(hashName, attrPtr);
this->m_Attributes.insert(attributePair);
return true;
}
*/
}

template<class T>
Attribute<T>* Entity::getAttribute(std::string name)
{
uint nameHash = System::hash(name);

std::map<uint, void*>::iterator it;
for(it = this->m_Attributes.begin(); it != this->m_Attributes.end(); it++)
{
if((*it).first == nameHash)
//return static_cast<T*>((*it).second);
return static_cast<Attribute<T>*>((*it).second);
}

return NULL;
}

template<class T>
T* Entity::getAttributeDataPointer(std::string name)
{
Attribute<T>* temp = this->getAttribute<T>(name);
return temp->GetDataPointer();
//return this->getAttribute(name)->GetDataPointer();
}

// Private

// Protected[/source]

And this is the line that provokes the error
[source lang="cpp"]Entity e;
e.addAttribute<float>("TEST");[/source]

And at last the error;
[source lang="java"]1>------ Build started: Project: ComponentBase, Configuration: Debug Win32 ------
1> main.cpp
1> Creating library i:\Cpp Projects\ComponentBase\Debug\ComponentBase.lib and object i:\Cpp Projects\ComponentBase\Debug\ComponentBase.exp
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall Entity::addAttribute<float>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$addAttribute@M@Entity@@QAEXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function _main
1>i:\Cpp Projects\ComponentBase\Debug\ComponentBase.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
[/source]

What does this error mean? And how can I fix it?

Share this post


Link to post
Share on other sites
Sorry for being such a dumb ass, but I can't figure out where my code is equal to that in the logical way. Could you please point out in my code / logic where my error is?

Share this post


Link to post
Share on other sites
The link states that you cannot, under usual circumstances, separate template definitions and declarations. The full definition of the template (which for functions mean the whole function body) has to be in the header file. You have separated the definition into a separate source file, and you cannot do that.

Share this post


Link to post
Share on other sites
So normal practice is if the method or class uses a template it must be in the header?

'Cause I moved the getAttribute to the Attribute.h but still no luck.

Share this post


Link to post
Share on other sites
Okey, now I got

Attribute.h
[source lang="cpp"]#if !defined OP_ATTRIBUTE
#define OP_ATTRIBUTE

#include "OPEngine.h"

template<class T>
class Attribute
{
public:
Attribute()
{
this->m_Data = new T;
}

T getData()
{
return *this->m_Data;
}

T* getDataPointer()
{
return &this->m_Data;
}

void setData(T data)
{
*this->m_Data = data;
}

private:

protected:
T* m_Data;

};

#endif[/source]

Entity.h
[source lang="cpp"]#if !defined OP_ENTITY
#define OP_ENTITY

#include "OPEngine.h"

class Entity
{
public:
void initialize();

bool attachComponent(Component* compPtr);

template<class T>
void addAttribute(std::string name)
{
if(this->m_Attributes.find(hashName) != this->m_Attributes.end())
{
WARN("Tried to register attribute but name was already taken");
return false;
}
else
{
void* attrPtr = new Attribute<T>();
std::pair<uint, void*> attributePair(hashName, attrPtr);
this->m_Attributes.insert(attributePair);
return true;
}
}

void handleMessage(Message* msg);

template<class T>
Attribute<T>* getAttribute(std::string name)
{
uint nameHash = System::hash(name);

std::map<uint, void*>::iterator it;
for(it = this->m_Attributes.begin(); it != this->m_Attributes.end(); it++)
{
if((*it).first == nameHash)
//return static_cast<T*>((*it).second);
return static_cast<Attribute<T>*>((*it).second);
}

return NULL;
}

template<class T>
T* getAttributeDataPointer(std::string name)
{
Attribute<T>* temp = this->getAttribute<T>(name);
return temp->GetDataPointer();
//return this->getAttribute(name)->GetDataPointer();
}


private:

protected:
sf::Vector2f m_Position;
float m_Rotation;
std::map<uint, Component*> m_Components;
std::map<uint, void*> m_Attributes;
uint m_EntityName;

};

#endif[/source]

Entity.cpp
[source lang="cpp"]#include "Entity.h"

// Public
bool Entity::attachComponent(Component* compPtr)
{
uint hashName = compPtr->getNameHash();
if(this->m_Components.find(hashName) != this->m_Components.end())
{
WARN("Tried to attach component but a component with the same name was already attached");
return false;
}
else
{
std::pair<uint, Component*> componentPair(hashName, compPtr);
this->m_Attributes.insert(componentPair);
LOG("Component successfully attached to entity");
return true;
}
}[/source]

And get the error
[source lang="cpp"]1>------ Build started: Project: ComponentBase, Configuration: Debug Win32 ------
1> Entity.cpp
1> Generating Code...
1> Skipping... (no relevant changes detected)
1> main.cpp
1> Component.cpp
1> Creating library i:\Cpp Projects\ComponentBase\Debug\ComponentBase.lib and object i:\Cpp Projects\ComponentBase\Debug\ComponentBase.exp
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall Entity::addAttribute<float>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$addAttribute@M@Entity@@QAEXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function _main
1>i:\Cpp Projects\ComponentBase\Debug\ComponentBase.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
[/source]

Share this post


Link to post
Share on other sites
Can't seem to edit my post: anyway, got it working now. Thanks! And I see now after reading the FAQ, linked over, for the 4th time, what I was doing wrong.

Share this post


Link to post
Share on other sites

This topic is 1989 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this