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.
Related
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()
{
}
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?
The following code reproduces an error that I get in VS2005: I have a template function like
template <typename T> bool foo(T x, T y) {
struct bar {
public:
T t;
bool CompLT(const bar& that) {
return (this->t) < (that.t);
}
};
bar X, Y;
X.t = x;
Y.t = y;
return X.CompLT(Y);
}
in a header file A.h. When I now use the header in two compilation units B.cpp and C.cpp VS2005 complains with the error
error LNK2005: "public: bool __thiscall `bool __cdecl foo<float>(float,float)'::`2'::bar::CompLT(struct `bool __cdecl foo<float>(float,float)'::`2'::bar const &)" (?CompLT#bar#?1???$foo#M##YA_NMM#Z#QAE_NABU1?1???$foo#M##YA_NMM#Z##Z) is already defined in B.obj .
How can I fix this error? Is this a problem with VS2005 or do I have to move the definition of the struct out of the local function scope and make it a template?
Have you used include guards ?
Try adding the following and remove any object file (ending with .o)
#ifndef A_H
#define A_H
//your header
#endif
From the comments being made it is clear that this is a bug in VS2005. As no one could provide some insight into the exact source of the problem I will give my solution: I moved the function into a static template class and defined the inner struct as a private local within that class template.
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
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;
}