This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
I'm relatively new to C++ and I feel like I'm in over my head. I'm trying to create a graph structure that can take any kind of data by using templates. Here is c_graph.h
#pragma once
#include <vector>
#include <unordered_map>
#include <unordered_set>
template <class T> class c_graph {
private:
std::unordered_map<T,std::unordered_set<T>> adj_matrix;
public:
'' GRAPH OPERATIONS OMITTED ''
};
template <class M> struct node {
public:
M val;
node() {
}
node(M v) {
val = v;
}
};
I would like to support using data directly (hence the template T on the graph), or wrapping the data in a node struct, which is defined at the bottom. My reason for the node struct is sometimes you want different nodes in the graph to have the same data, which wouldn't work with the unordered_map on the outside of the adjacency matrix without a data wrapper.
However I've run into an issue with the unordered_set class. It doesn't have a hash function for node. I read about this problem online and the solution seems to be something like
namespace std {
template <class M> class hash<node<M>> {
public:
size_t operator()(const node<M> &n) const
{
return reinterpret_cast<size_t>(&n);
}
};
};
I have another .cpp file that is trying to use c_graph<node<char>>
However for the life of me I can't get my code to compile. I've tried placing the hash snippet inside c_graph.h, where I get a bunch of linker errors
error LNK2019: unresolved external symbol "public: void __thiscall c_graph<struct node<char> >::add_node(struct node<char>)"...
and I've tried placing it inside c_graph.cpp, where I get
error C2338: The C++ Standard doesn't provide a hash for this type.
Turns out you can't really separate template function declarations from template function implementations. Linker error when using a template class?
Moving the contents of c_graph.cpp into c_graph.h got rid of the linker errors
Related
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Static member initialization in a class template
(3 answers)
Closed 4 years ago.
Let's say for some reason, I want to have a class template MyTemp with some static data member smDummyVar :
Mytemp.h
#ifndef MY_TEMP_H
#define MY_TEMP_H
template<class T>
class MyTemp{
...
private:
static int smDummyVar;
...
};
#include "MyTemp.cpp"
#endif //MY_TEMP_H
Mytemp.cpp
...
template<class T> int MyTemp<T>::smDummyVar = 0;
...
Since the compiler requires that the definition and declaration of a template be at the same place, so I include MyTemp.cpp in MyTemp.h .
Now: I want to use MyTemp at many places and create objects using the template:
case1.cpp
#include "MyTemp.h"
void dummyfunc1(){
MyTemp<int> myTemp1;
}
case2.cpp
#include "MyTemp.h"
void dummyfunc2(){
MyTemp<int> myTemp2;
}
I won't get any error from the compiler, but I'd get warning from the linker:
"multiple definition for MyTemp<int>::smDummyVar" ... defined in invalid_group(case1.o) ... rejected in favour of symbol defined in ...(case2.o)
Question: how can I get rid of this warning ?
Thanks a lot in advance for your help !
====================================
inspired by one of the answers in this thread Why can templates only be implemented in the header file?
I found the following solution:
i. remove #include "MyTemp.cpp" in MyTemp.h
ii. specialized.h
#include "MyTemp.h"
typedef MyTemp<int> MySpecialized;
iii. specialized.cpp
#include "MyTemp.cpp"
template class MyTemp<int>;
iv. give specialized.cpp to cmake file
v. include specilized.h in case1.cpp and case2.cpp
the "multiple definition" warning issued by the linker will go away.
Thank you guys for helping !
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 5 years ago.
Let's say we have base class Table
template <typename T>
class Table
{
public:
Table();
virtual ~Table() = default;
private:
// get all column names as list
virtual std::list<std::string> getAllColumnsImpl();
};
and I want inherit TestTable class and override method getAllColumnsImpl from base class:
class TestTable :
public Table<TestTable>
{
public:
TestTable();
virtual ~TestTable() = default;
std::string Description;
int Count;
private:
// get all column names as list
std::list<std::string> getAllColumnsImpl() override;
};
Is it possible in general ?
For example I have linker errors like:
error LNK2019: unresolved external symbol "public: __cdecl Table<class TestTable>::Table<class TestTable>(void)" (??0?$Table#VTestTable####QEAA#XZ) referenced in function "public: __cdecl TestTable::TestTable(void)" (??0TestTable##QEAA#XZ)
You can do it, it's called CRTP - the Curiously Recurring Template Parameter. It's very handy and there are many blogs and resources explaining uses for it.
The error you're getting is because you need to have the template's function bodies in the template's header file.
Each cpp file is compiled to a separate object file, and templates are resolved on a per-cpp file basis. When you put template code in a cpp file, then it's just "template < T >" and the compiler doesn't know what T is, so no code is generated (unless it's requested from the same cpp file, with an actual type and not T).
However, your other cpp file knows that it wants a "template < TestTable >", but it doesn't have access to the code that would make that work, because that's stuck in the other cpp file, which only knows the generic "template < T >". Neither cpp file is able to generate the missing code, so you get the linker error. Putting all the template code together in the header file removes the issue.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
I'm trying to learn how to use templated classes. I've created a simple templated class numbers that holds 2 numbers that can be any data type. Then I made a method that returns the bigger number of the two in the object. For some reason I keep getting linker errors though... Here's the errors and code. Not sure what's wrong, Visual Studio didn't underline anything in my code.
They say "unresolved external symbol" if it's too small to read.
templated.h
template <class T>
class numbers {
public:
numbers(T x, T y);
T bigger();
private:
T a, b;
};
templated.cpp
#include "templated.h"
#include <iostream>
using namespace std;
template <class T>
numbers<T>::numbers(T x, T y) {
a = x;
b = y;
}
template <class T>
T numbers<T>::bigger() {
return a > b ? a : b;
}
main.cpp
#include <iostream>
#include "templated.h"
using namespace std;
int main() {
numbers <int>pair(1, 2);
cout << pair.bigger() << endl;
return 0;
}
Thanks for reading!
You're not supposed to put template implementations in a cpp/c file. Move them all to your .h file.
This is because cpp files are supposed to take functions that compile into implementation libraries (like dll files or compiled objects), while template functions have undefined types (yet), whose types get defined at compile time.
You can, however, put specializations of your template functions in the cpp file, where you specify what types you want to include in your compiled objects.
For the upcoming Coursework in January, I started developing a small DirectX engine. To find out if there is a performance increase I wanted to try to not use any virtuals at all (I know that virtuals aren't all bad, but I just wanted to see if it is possible without them).
When I started playing around with a simple StateManager, it got hard to avoid virtuals, but this is my current approach:
#include <boost\function.hpp>
#include <boost\bind.hpp>
template <class Derived>
struct TBaseState {
bool update(float delta) {
return static_cast<Derived *>(this)->update(delta);
};
};
struct CTestState : TBaseState<CTestState> {
bool update(float delta) {
return true;
}
};
class StateManager
{
public:
template <class StateClass> static void setState(StateClass nextState)
{
m_funcptrUpdate = boost::bind(&TBaseState<StateClass>::update, boost::ref(nextState), _1);
}
static bool update(float delta)
{
return m_funcptrUpdate(delta);
}
protected:
private:
static boost::function<bool (float)> m_funcptrUpdate;
};
Visual Studio 2010's Intellisense seems to think everything is fine, but when I want to compile the program and test the StateManager with a very basic approach:
CTestState* t = new CTestState();
StateManager::setState(*t);
StateManager::update(0.0f);
The following error is thrown during linking phase:
error LNK2001: unresolved external symbol "private: static class boost::function<bool __cdecl(float)> StateManager::m_funcptrUpdate" (?m_funcptrUpdate#StateManager##0V?$function#$$A6A_NM#Z#boost##A)
So obviously he can't find the binded function, but how can I solve this issue? I get similar errors if I use boost::bind directly to some class. Since I am a computer science student I would also be interested in some insight or approaches without boost (e.g. bind1st, ...).
EDIT:
I was also thinking about using C++11 Variadic Templates, but one of the coursework requirements is to stick to VS2012.
Static class members need to be given storage. They're like extern variables. Add a definition to one of your .cpp files, outside of the class definition:
boost::function<bool (float)> StateManager::m_funcptrUpdate;
Also, in this code:
template <class StateClass> static void setState(StateClass nextState)
{
m_funcptrUpdate = boost::bind(&TBaseState<StateClass>::update,
boost::ref(nextState), _1);
}
You're maintaining storing a reference to the local variable nextState. That reference will be invalid after setState returns.
When I put all the source in one file, the program successfully builds. However when I split them into header files, I get a link error.
The main of my program:
//C++_Class_Templates.cpp
#include <iostream>
#include <vector>
#include "Queue.h"
using namespace std;
//Usage for C++ class templates
void main()
{
MyQueue<int> q;
q.Add(1);
q.Add(2);
}
The Queue.h looks like this
#pragma once
#include <vector>
template <typename T>
class MyQueue
{
std::vector<T> data;
public:
void Add(T const &);
void Remove();
void Print();
};
and the Queue.cpp looks like this:
#include "Queue.h"
template <typename T> void MyQueue<T> ::Add(T const &d)
{
data.push_back(d);
}
When I try to build it, I get this error:
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall
MyQueue<int>::Add(int const &)" (?Add#?$MyQueue#H##QAEXABH#Z) referenced in function _main
The short answer is: "you don't."
The longer answer is: well, it's basically the same as the short answer. For more information, see the C++ FAQ Lite entry "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?" Except for certain limited-use scenarios (like when you have a small set of known arguments with which you will use the template and you can explicitly instantiate it with those types), the definition of the template must be available when you try to use it.
Separating declaration and definition for templates is not trivial.
The compiler must see the definition to be able to compile a specialization but it must also know the parameters to use. C++ was designed to be compiled one "compile unit" at a time and those two parts (the definition and the parameters) must be visible at the same time.
So either you put all a list of all specializations you will need in the implementation file of the template or you put the whole definition in the .h file. Both of those two solutions have however drawbacks.
See this answer to the same problem you are facing for a more complete explanation.