Unable to Link C++ Code - c++

I have the following three files in the same directory:
citysim.cpp
#include "utils.h"
using namespace std;
int main()
{
City *c;
c = new City();
Graph<City *> g;
g.addVertex(c);
}
utils.h
#include <iostream>
#include <map>
#include <vector>
using namespace std;
class City {
public:
City() {}
private:
string name;
};
template <typename Tkey>
class Graph {
public:
Graph() {}
void addVertex(Tkey);
private:
vector<Tkey> v;
vector< vector<int> > e;
map<Tkey, int> key_map;
};
utils.cpp
#include "utils.h"
template <typename Tkey>
void Graph<Tkey>::addVertex(Tkey vertex)
{
v.push_back(vertex);
}
And I am really perplexed as to why the following compilation sequence produces the result indicated:
test> g++ -c citysim.cpp
test> g++ -c utils.cpp
test> g++ -o citysim citysim.o utils.o
citysim.o: In function `main':
citysim.cpp:(.text+0x4a): undefined reference to `Graph<City*>::addVertex(City*)'
collect2: ld returned 1 exit status
Any ideas or insights are appreciated!

Define everything of your templated class in your header file, not in a cpp file. Instead of having your utils.cpp have everything like this in your header file:
template <typename Tkey>
class Graph {
public:
Graph() {}
void addVertex(Tkey vertex)
{
v.push_back(vertex);
}
private:
vector<Tkey> v;
vector< vector<int> > e;
map<Tkey, int> key_map;
};
Here is the related reading in the faq...
EDIT:
(But you can define it later on like you did it in your cpp in the header file as well...)

Template functions must be written entirely on the header, their definitions can't go on the cpp file.

Related

Undefined reference to a function in a class defined in anther file while using typename

I have been stuck for a while now and am unable to figure out why I am getting this compile error.
Node.hpp
#ifndef H1
#define H1
template <typename T>
class Node{
private:
T data;
public:
T getData();
};
#endif
Node.cpp
#include "Node.hpp"
template<typename T>
T Node<T>::getData(){
return data;
}
main.cpp
#include <bits/stdc++.h>
#include "Node.hpp"
using namespace std;
int main()
{
Node<int> *n = new Node<int>();
cout << n->getData();
}
g++ main.cpp Node.cpp -std=c++17
O/P: main.cpp:(.text+0x24): undefined reference to `Node::getData()'collect2: error: ld returned 1 exit status
PS: I tried the same thing without any template (use a primitive datatype instead), I do not get any error. So this probably has got something to do with the typename. Would be great if someone could tell me what is wrong here.
Node.hpp
#ifndef H1
#define H1
template <typename T>
class Node{
private:
T data;
public:
T getData() { return data; }
};
//or define it here
#endif
Then no need for Node.cpp. You might want to consider returning a const reference if your use-case allows it as T now requires a copy constructor. Although maybe that's what you want, I don't know your use-case.
See Why can template only be defined in header files

Template error : undefined reference

I am trying to create a class linkedList using template but when I compile it the IDE gives an error :
undefined reference to `listType::add(int)
I am not understanding why ?
linkedList.h
#ifndef LINKEDLISTS_H_INCLUDED
#define LINKEDLISTS_H_INCLUDED
#include "struct.h"
template <class type1>
class listType
{
public:
void add(type1);
void print();
private:
node<type1> *head;
};
#endif // LINKEDLISTS_H_INCLUDED
LinkedList.cpp
#include "linkedLists.h"
#include "struct.h"
#include <iostream>
using namespace std;
template <class type1>
void listType<type1>::add(type1 temp)
{
node<type1> *t;
t->value=temp;
t->link=head;
head=t;
}
template <class type1>
void listType<type1>::print()
{
node<type1> *p;
p=head;
while(p!=NULL)
{
cout<<p->value<<endl;
p=p->link;
}
}
Struct.h
#ifndef STRUCT_H_INCLUDED
#define STRUCT_H_INCLUDED
template <class type1>
struct node
{
type1 value;
node *link;
};
#endif // STRUCT_H_INCLUDED
main.cpp
#include <iostream>
#include "linkedLists.h"
using namespace std;
int main()
{
listType <int> test;
test.add(5);
}
You can't have the implementation of templated classes and functions in the cpp file.
The code has to be in the header, so the including files can see the implementation, and instantiate the correct version with their template argument type.

hello to boost multi index

I have started working on a project that incorporates some of boost libraries(thread and MPI).
I am going to use boost multi_index in one of the modules which is not using boost at all.FYI this project has not used boost multi index before)
as soon as I tried to include
boost/multi_index_container.hpp
to the file and built the projects, I received a number of errors starting with the following:
Building CXX object CMakeFiles/SimMobility.dir/main.cpp.o
/usr/bin/c++ -fmessage-length=0 -DBOOST_NO_HASH -O0 -g -I/usr/include/postgresql -I/usr/include/soci -I/usr/include/soci/postgresql -I/usr/include/xsd -I/home/vahid/workspace/Basic__Multi_index -o CMakeFiles/SimMobility.dir/main.cpp.o -c /home/vahid/workspace/Basic__Multi_index/main.cpp
In file included from /usr/include/boost/multi_index/detail/node_type.hpp:22:0,
from /usr/include/boost/multi_index/detail/index_base.hpp:21,
from /usr/include/boost/multi_index/detail/base_type.hpp:21,
from /usr/include/boost/multi_index_container.hpp:33,
from /home/vahid/workspace/Basic__Multi_index/geospatial/RoadNetwork.hpp:10,
from /home/vahid/workspace/Basic__Multi_index/main.cpp:25:
/usr/include/boost/multi_index/detail/header_holder.hpp:41:16: error: expected unqualified-id before ‘)’ token
/usr/include/boost/multi_index/detail/header_holder.hpp: In constructor ‘boost::multi_index::detail::header_holder<NodeTypePtr, Final>::header_holder()’:
/usr/include/boost/multi_index/detail/header_holder.hpp:35:32: error: expected primary-expression before ‘)’ token
may I know what the problem is? is it cmake not finding what it needs? any idea how to solve it?
Edit:
in case you want to have a look at the source code, here is a simplified version:
RoadNetwork.hpp:
#pragma once
#include <iostream>
#include <vector>
#include <set>
#include <boost/multi_index_container.hpp> //causing problem!!!!!!!
namespace geo {class Links_pimpl;}
namespace sim_mob
{
//Forward declarations
class Node;
class UniNode;
class MultiNode;
class Point2D;
class Link;
namespace aimsun
{
//Forward declaration
class Loader;
}
//typedef multi_index_container<
//sim_mob::Link,
// indexed_by<
// random_access<>,
//// ordered_unique< member<sim_mob::Link, std::string, &sim_mob::Link::linkID> >
// >
//> Link_m;
class RoadNetwork {
public:
RoadNetwork() { drivingSide=DRIVES_ON_LEFT; } //TEMP
sim_mob::Node* locateNode(const sim_mob::Point2D& position, bool includeUniNodes=false, int maxDistCM=100) const;
private:
std::vector<sim_mob::MultiNode*> nodes;
std::vector<sim_mob::Link*> links;
std::vector<sim_mob::MultiNode*>& getNodesRW() { return nodes; }
std::set<sim_mob::UniNode*>& getUniNodesRW() { return segmentnodes; }
std::vector<sim_mob::Link*>& getLinksRW() { return links; }
friend class sim_mob::aimsun::Loader;
friend class geo::Links_pimpl;
};
}
Thank you your kind help
vahid
I modified your header to look like this:
#pragma once
#include <iostream>
#include <vector>
#include <set>
#include <boost/multi_index_container.hpp> //causing problem!!!!!!!
using boost::multi_index_container;
namespace geo {class Links_pimpl;}
namespace sim_mob
{
//Forward declarations
class Node;
class UniNode;
class MultiNode;
class Point2D;
class Link;
namespace aimsun
{
//Forward declaration
class Loader;
}
//typedef multi_index_container<
//sim_mob::Link,
// indexed_by<
// random_access<>,
// ordered_unique< member<sim_mob::Link, std::string, &sim_mob::Link::linkID> >
// >
//> Link_m;
class RoadNetwork {
int drivingSide;
enum side { DRIVES_ON_LEFT, DRIVES_ON_RIGHT};
public:
RoadNetwork() { drivingSide=DRIVES_ON_LEFT; } //TEMP
sim_mob::Node* locateNode(const sim_mob::Point2D& position, bool includeUniNodes=false, int maxDistCM=100) const;
private:
std::vector<sim_mob::MultiNode*> nodes;
std::vector<sim_mob::Link*> links;
std::set<sim_mob::UniNode*> segmentnodes;
std::vector<sim_mob::MultiNode*>& getNodesRW() { return nodes; }
std::set<sim_mob::UniNode*>& getUniNodesRW() { return segmentnodes; }
std::vector<sim_mob::Link*>& getLinksRW() { return links; }
friend class sim_mob::aimsun::Loader;
friend class geo::Links_pimpl;
};
}
Then I included it in a small file that instantiated a RoadNetwork object:
#include <iostream>
#include "roadnetwork.hpp"
int main() {
sim_mob::RoadNetwork roads;
return 0;
}
This compiled, linked, and executed (though produced no output).
Not entirely sure what problem you're encountering...
I encountered the same problem and tracked it down. Do you have by chance a #define final somewhere in your sources before including boost/multi_index.hpp or a -Dfinal in your compiler settings? In my case that was the problem, I use the C++11 keywords final and override in my classes and had to define them when using older compilers.
Or, maybe it's some other identifier used by multi_index that you have defined somewhere. You could dump all your defined macros as described here and check if disabling one of them helps.
I also encountered similar problem.
I got compile error in
multi_index header_holder file.
warning : final key word is blah... blah...
So I changed the
#include <boost/xxxxx>
position to other place.
( ex: stdafx.h etc ... )
Try this one.

How to compile a templated class (C++) in Eclipse?

I'm trying to create a linked list class in Eclipse but I can't get it to compile properly.
Here is my .cc file (code snipet)
#include <iostream>
#include "list.h"
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
and here is my list.h file (code snipet)
#ifndef __LIST_H__
#define __LIST_H__
template <typename T>
class List {
public:
bool isEmpty();
private:
struct node {
node *following;
node *previous;
T *contents;
};
node *firstNode;
};
#include "list.cc"
#endif /* __LIST_H__ */
I try "Building All" in eclipse but I get the following error:
make all
Building file: ../list.cc
Invoking: Cross G++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"list.d" -MT"list.d" -o "list.o" "../list.cc"
../list.cc:13: error: redefinition of 'bool List<T>::isEmpty()'
../list.cc:13: error: 'bool List<T>::isEmpty()' previously declared here
make: *** [list.o] Error 1
Help please...thanks. I'll be happy to provide any clarifications needed
EDIT: I was given the .h file so I know that it is correct. I also know that I am supposed to have a .cc file called list.cc (it is included at the end of the .h file)
You need to change the extension of the file with the implementation.
The compiler will process this file for compilation and will process it twice, since you're including it in the header.
Your file looks like this:
#include <iostream>
#include "list.h"
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
which will become
#include <iostream>
#ifndef __DLIST_H__
#define __DLIST_H__
template <typename T>
class List {
public:
bool isEmpty();
private:
struct node {
node *following;
node *previous;
T *contents;
};
node *firstNode;
};
#include "dlist.cc"
#endif /* __DLIST_H__ */
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
which will in turn become
#include <iostream>
#ifndef __DLIST_H__
#define __DLIST_H__
template <typename T>
class List {
public:
bool isEmpty();
private:
struct node {
node *following;
node *previous;
T *contents;
};
node *firstNode;
};
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
#endif /* __DLIST_H__ */
using namespace std;
template <class T>
bool List<T>::isEmpty()
{
return (firstNode == NULL);
}
So the function isEmpty() is defined twice.
Rename the file to dlist.impl.
Try putting the definition for List<T>::isEmpty() in the same file as the class is declared.
Given the unusual form of the header you've been supplied with, to test it you will need another source file. To start with the new source file (say test.cpp) can just #include "list.h", which will check for any syntax errors but will not yet instantiate your List template.
(Just compile test.cpp, not list.cc, since list.cc is indirectly included by test.cpp)

Linking error in C++

Problem fixed. Thanks a lot!
I am having the following error in the code shown below:
Error is as follows:
$ g++ main.cpp Neighbor.cpp Graph.cpp
/tmp/ccclDcUN.o: In function main':
main.cpp:(.text+0xc1): undefined reference toGraph::add(int, Neighbor&)'
main.cpp:(.text+0xd3): undefined reference to `Graph::add(int, Neighbor&)'
collect2: ld returned 1 exit status
what could be going wrong?
// FILENAME: Graph.cpp
#include "Neighbor.h"
#include "Graph.h"
template <typename NS>
void Graph<NS>::add(int id,NS& n){
if(id>=adj_list.size())
while(adj_list.size()<id+1)
adj_list.push_back(list<NS>());
adj_list[id].push_back(n);
}
template <typename NS>
void Graph<NS>::remove(int id,NS& n){
if(id<adj_list.size()){
adj_list[id].remove(n);
}
}
// FILENAME: Graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include "utils.h"
#include <vector>
#include <list>
class Neighbor;
template <typename NS>
class Graph {
private:
std::vector<std::list<NS> > adj_list;
public:
void add(int,NS&);
void remove(int,NS&);
inline typename std::vector<std::list<NS> >::iterator begin() { return adj_list.begin(); }
inline typename std::vector<std::list<NS> >::iterator end() { return adj_list.end(); }
};
#endif
// FILENAME: Neighbor.cpp
#include "Neighbor.h"
#include <iostream>
Neighbor::Neighbor(int id,float e,float p):id(id),edge_cost(e),price(p){}
bool operator==(const Neighbor& n1,const Neighbor& n2) {
if(&n1==&n2) return true;
return false;
}
ostream& operator<<(ostream& ostr,const Neighbor& n1) {
ostr<<"["<<n1.id<<","<<n1.price<<","<<n1.edge_cost<<"]";
return ostr;
}
// FILENAME: Neighbor.h
#ifndef NEIGHBOR_H
#define NEIGHBOR_H
#include <iosfwd>
class Neighbor {
private:
int id;
float edge_cost;
float price;
public:
Neighbor(int,float,float p=0.0);
friend bool operator==(const Neighbor&,const Neighbor&);
friend std::ostream& operator<<(std::ostream&,const Neighbor&);
};
#endif
// FILENAME: utils.h
#ifndef UTILS_H
#define UTILS_H
#include <iostream>
#include <fstream>
#include <stack>
#include <queue>
#include <vector>
#include <list>
#include <string>
#include <algorithm>
namespace utility {
typedef std::pair<int,int> ii;
typedef std::vector<int> vi;
typedef std::vector<ii> vii;
typedef std::vector<vii> vvii;
typedef std::stack<int> si;
typedef std::queue<int> qi;
}
#define UTILITY_TR(c,i) for(typeof((c).begin()) i = (c).begin() ; i!=(c).end() ; ++i )
#define UTILITY_ALL(c) (c).begin(),(c).end()
#define UTILITY_CPRESENT(c,x) (find(all(c),x) != (c).end())
#endif
// FILENAME: main.cpp
#include "utils.h"
#include "Neighbor.h"
#include "Graph.h"
using namespace std;
int main() {
Graph<Neighbor> graph;
Neighbor n1(1,10);
Neighbor n2(0,10);
graph.add(0,n1);
graph.add(1,n2);
cout<<"Printing graph"<<endl;
cout<<"--------------"<<endl;
UTILITY_TR(graph,it) {
UTILITY_TR(*it,n) {
cout<<*n<<endl;
}
}
};
What I usually do is manually verify the symbol exists in the library:
objdump --syms foo.o
This will output a list of symbols contained in the .o file... (since it's a link error, you should have .o files... (make sure you pass -c to g++ to get it to stop after compilation))... Then you can just visually verify the object has the symbols you think it does...
You need to have the definition of Graph's functions (add and remove) in the .h file so that the linker can find it.
I try to think of templates like envelopes. It's nonsensical to send it (compile) before you put in a letter (defined type). Seeing as cpp files are what is compiled, it makes sense that there shouldn't be cpp files for templated types.
HTH!