-
Linker errors
I have a header file which contains the class with only function declarations. I then define the function in a separate cpp file. However, I get linker errors when I do this. If I define the function in the header file (but outside the class) I don't get linker errors. Why would it matter whether the function was defined inside the header or cpp file?
The function insertVertex is giving me problems.
GraphEdgeList.h
Code:
#ifndef GRAPHEDGELIST_H
#define GRAPHEDGELIST_H
#include <vector>
#include <list>
template <typename Object>
class Vertex {
private:
template <typename> friend class GraphEdgeList;
Object o;
int undirectedDegree;
int inDegree;
int outDegree;
public:
Vertex(const Object& oo = Object()) : o(oo), undirectedDegree(0),
inDegree(0), outDegree(0)
{
}
const Object& element() const {
return o;
}
void element(const Object& oo) {
o = oo;
}
};
template <typename Object>
class Edge {
private:
template <typename> friend class GraphEdgeList;
typedef Vertex<Object> Vertex;
Object o;
Vertex* origin;
Vertex* destination;
bool isDirected;
public:
Edge(const Object& oo = Object(), Vertex* org = NULL, Vertex* dst = NULL,
bool directed = false)
: o(oo), origin(org), destination(dst), isDirected(directed)
{
}
const Object& element() const {
return o;
}
void element(const Object& oo) {
o = oo;
}
};
/*
* A graph represented by an edge list
*/
template <typename Object>
class GraphEdgeList {
typedef Vertex<Object> Vertex;
typedef Edge<Object> Edge;
std::list<Vertex> V;
std::list<Edge> E;
public:
Vertex& insertVertex(const Object& o);
};
#ifdef DEFINEINHEADER
template <class Object>
typename GraphEdgeList<Object>::Vertex&
GraphEdgeList<Object>::insertVertex(const Object& o) {
typedef typename GraphEdgeList<Object>::Vertex Vertex;
V.push_back(Vertex(o));
return V.back();
}
#endif
#endif
GraphEdgeList.cpp
Code:
#include "GraphEdgeList.h"
#ifdef DEFINEINCPP
template <class Object>
typename GraphEdgeList<Object>::Vertex&
GraphEdgeList<Object>::insertVertex(const Object& o) {
typedef typename GraphEdgeList<Object>::Vertex Vertex;
V.push_back(Vertex(o));
return V.back();
}
#endif
main.cpp
Code:
#define DEFINEINCPP // this gives linker errors
//#define DEFINEINHEADER // this works
#include "GraphEdgeList.h"
#include <iostream>
#include <utility>
#include <string>
int main() {
GraphEdgeList<std::string> g;
g.insertVertex("SFO");
}
-
-
From what I read, I just have to add another line to the cpp file. However, I'm still getting linker errors. What am I doing wrong?
Code:
#include "GraphEdgeList.h"
#ifdef DEFINEINCPP
template <class Object>
typename GraphEdgeList<Object>::Vertex&
GraphEdgeList<Object>::insertVertex(const Object& o) {
typedef typename GraphEdgeList<Object>::Vertex Vertex;
V.push_back(Vertex(o));
return V.back();
}
template class GraphEdgeList<std::string>; // added this line
#endif
-
You have to add
Code:
#define DEFINEINCPP
into GraphEdgeList.cpp as well, otherwise it won't be defined. Of course, this is duplication of code, so I'd suggest adding the DEFINEIN* to another .h file which you then include in GraphEdgeList.h. That should solve the problem.
Also, by the way, I had compiler errors when compiling your code with g++ 4.3 and g++ 4.4. It doesn't like you doing things like this:
Code:
typedef Vertex<Object> Vertex;
Erros:
Code:
GraphEdgeList.h:56: error: declaration of ‘typedef class Vertex<Object> GraphEdgeList<Object>::Vertex’
GraphEdgeList.h:8: error: changes meaning of ‘Vertex’ from ‘class Vertex<Object>’
If I were you I'd pick a different name.
[edit] In case you're interested, here's the code I got to compile with g++ 4.3.
Code:
$ for file in *.cpp *.h; do echo === $file; cat $file; done
=== GraphEdgeList.cpp
#define DEFINEINCPP // this gives linker errors
#include "GraphEdgeList.h"
#ifdef DEFINEINCPP
template <class Object>
typename GraphEdgeList<Object>::Vertex_&
GraphEdgeList<Object>::insertVertex(const Object& o) {
//typedef typename GraphEdgeList<Object>::Vertex Vertex;
V.push_back(Vertex_(o));
return V.back();
}
#include <string>
template class GraphEdgeList<std::string>; // added this line
#endif
=== main.cpp
#define DEFINEINCPP // this gives linker errors
//#define DEFINEINHEADER // this works
#include "GraphEdgeList.h"
#include <iostream>
#include <utility>
#include <string>
int main() {
GraphEdgeList<std::string> g;
g.insertVertex("SFO");
}
=== GraphEdgeList.h
#ifndef GRAPHEDGELIST_H
#define GRAPHEDGELIST_H
#include <vector>
#include <list>
template <typename Object>
class Vertex {
private:
template <typename> friend class GraphEdgeList;
Object o;
int undirectedDegree;
int inDegree;
int outDegree;
public:
Vertex(const Object& oo = Object()) : o(oo), undirectedDegree(0),
inDegree(0), outDegree(0)
{
}
const Object& element() const {
return o;
}
void element(const Object& oo) {
o = oo;
}
};
template <typename Object>
class Edge {
private:
template <typename> friend class GraphEdgeList;
typedef Vertex<Object> Vertex_;
Object o;
Vertex_* origin;
Vertex_* destination;
bool isDirected;
public:
Edge(const Object& oo = Object(), Vertex_* org = NULL, Vertex_* dst = NULL,
bool directed = false)
: o(oo), origin(org), destination(dst), isDirected(directed)
{
}
const Object& element() const {
return o;
}
void element(const Object& oo) {
o = oo;
}
};
/*
* A graph represented by an edge list
*/
template <typename Object>
class GraphEdgeList {
typedef Vertex<Object> Vertex_;
typedef Edge<Object> Edge_;
std::list<Vertex_> V;
std::list<Edge_> E;
public:
Vertex_& insertVertex(const Object& o);
};
#ifdef DEFINEINHEADER
template <class Object>
typename GraphEdgeList<Object>::Vertex&
GraphEdgeList<Object>::insertVertex(const Object& o) {
//typedef typename GraphEdgeList<Object>::Vertex Vertex_;
V.push_back(Vertex(o));
return V.back();
}
#endif
#endif
$
Notice the #include <string> and the typedefs changed to Vertex_ etc. [/edit]