Multiple defined linker error for getting static member variable template - c++

When I have a class that can be boiled down to something like this:
// test.hpp
class Test{
public:
template<typename T> static T value;
};
template<typename T> Test::value = {};
I can use this class when I only look up an instantiated value in one .cpp file. But when I try to use this in multiple .cpp files I get an already defined linker error.
//somefile1.cpp
include "test.hpp"
void fn(){
int i = Test::value<int>;
}
// somefile2.cpp
include "test.hpp"
void otherfn(){
// public static int value already defined in somefile1.obj
int j = Test::value<int>;
}
Putting template<typename T> Test::value = {} into its own .cpp file gives an unresolved external error for all uses. What's the problem?

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()
{
}

Unresolved External Symbol in Singleton Class

I've been coding for a long time now but I do not understand this error. I am writing a custom system for providing unique integer ID's to specific instances of objects (I call them tags). And I am implementing one of the classes as a Singleton.
The two classes for the Tagging system are defined as such:
#include "singleton.h"
class Tag: public bear::Singleton<Tag>
{
public:
static dUINT32 RequestTag(Tagged* requester);
static void RevokeTags(void);
private:
Tag(void);
~Tag(void);
Tagged** m_tagTable; // list of all objects with active tags
dUINT32 m_tagTable_capacity, // the maximum capacity of the tag table
m_tagIndexer; // last given tag
};
class Tagged
{
friend class Tag;
public:
inline dUINT32 GetTag(void) {return m_tag;}
private:
inline void InvalidateTag(void) {m_tag=INVALID_TAG;}
dUINT32 m_tag;
protected:
Tagged();
virtual ~Tagged();
};
The Singleton class is defined as such:
template <typename T>
class Singleton
{
public:
Singleton(void);
virtual ~Singleton(void);
inline static T& GetInstance(void) {return (*m_SingletonInstance);}
private:
// copy constructor not implemented on purpose
// this prevents copying operations any attempt to copy will yield
// a compile time error
Singleton(const Singleton<T>& copyfrom);
protected:
static T* m_SingletonInstance;
};
template <typename T>
Singleton<T>::Singleton (void)
{
ASSERT(!m_SingletonInstance);
m_SingletonInstance=static_cast<T*>(this);
}
template <typename T>
Singleton<T>::~Singleton (void)
{
if (m_SingletonInstance)
m_SingletonInstance= 0;
}
I am getting the following error upon trying to compile and link together the files:
test.obj : error LNK2001: unresolved external symbol "protected: static class util::Tag * bear::Singleton::m_SingletonInstance" (?m_SingletonInstance#?$Singleton#VTag#util###bear##1PAVTag#util##A)
1>C:...\tools\Debug\util.exe : fatal error LNK1120: 1 unresolved externals
Does anyone have any idea why I am getting this error?
You should provide a definition for your static data member at namespace scope (currently, you only have a declaration):
template <typename T>
class Singleton
{
// ...
protected:
static T* m_SingletonInstance; // <== DECLARATION
};
template<typename T>
T* Singleton<T>::m_SingletonInstance = nullptr; // <== DEFINITION
If you are working with C++03, you can replace nullptr with NULL or 0.

Trivial specialization of a method does not work (c++)

The following code (this is a simplified version of what I need) does not link
In *.h file:
class InterfaceFunctionField2 {
public:
template<class outputType> outputType to() { return outputType(); }
};
In *.cpp file
template<> double InterfaceFunctionField2::to<double>()
{ return 3.; }
This class sits in a static library.
I am getting "error LNK2005: "public: double __thiscall InterfaceFunctionField2::to(void)const " (??$to#N#InterfaceFunctionField2##QBENXZ) already defined in ..." and a "second definition ignored" warning LNK4006
I define InterfaceFunctionField2::to() specialization only once and I do not #include *.cpp files....
I have looked up on internet (e.g. here) and this type of code seems to be ok but the linker disagrees. Could you help? Thanks.
You need to also declare the specialization in the header.
//header.h
class InterfaceFunctionField2 {
public:
template<class outputType> outputType to() { return outputType(); }
};
template<> double InterfaceFunctionField2::to<double>();
//implementation.cc
template<> double InterfaceFunctionField2::to<double>()
{ return 3.; }
The code in your link works because the specialization is visible to that translation unit.

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