I have a problem with the linking of a C++ project and I can't figure out what's wrong.
The jest of the code.
clitest.cpp
#include <iostream>
#include "node.h"
using namespace std;
int main(int argc, char** argv)
{
node<int> *ndNew = new node<int>(7);
return 0;
}
node.h
#ifndef NODE_H
#define NODE_H
#include <vector>
template <typename T>
class node
{
private:
node<T>* ndFather;
std::vector<node<T>* > vecSons;
public:
T* Data;
node(const T &Data);
};
#endif
node.cpp
#include "node.h"
using namespace std;
template <typename T>
node<T>::node(const T &Data)
{
this->Data = &Data;
this->ndFather = 0;
this->vecSons = (new vector<T>());
};
The compiler command that was used is
g++ -Wall -g clitest.cpp node.cpp -o clitest
The error log is goes like this
clitest.cpp: In function ‘int main(int, char**)’:
clitest.cpp:8:16: warning: unused variable ‘ndNew’ [-Wunused-variable]
node<int> *ndNew = new node<int>(7);
^
/tmp/cc258ryG.o: In function `main':
clitest.cpp:8: undefined reference to `node<int>::node(int const&)'
collect2: error: ld returned 1 exit status
make: *** [blist] Error 1
I have spent a decent amount of time shifting the code around, Trying to identify the problem and I either miss something basic, Or it's something I don't know about C++ linkage.
When using templates, the compiler needs to know how to generate the code for the class when it is instantiated. The undefined reference error is caused because the compiler did not generate the node<int>::node(int const &) constructor. See, e.g. Why can templates only be implemented in the header file?
You have a couple of options:
Put the implementation in node.h (node.cpp is removed as it not needed)
Put the implementation in a file that is #included at the bottom of node.h (usually the file would be called node.tpp)
I suggest putting the implementation in node.h and removing node.cpp. Note that the code in your example is not valid c++: the member variable vecSons is not a pointer so the line vecSons = new vector<T>() will give a compiler error. The following code could be a starting point for the full implementation:
#ifndef NODE_H
#define NODE_H
#include <vector>
template <typename T>
class node
{
private:
node<T>* ndFather;
std::vector<node<T>* > vecSons;
public:
const T* Data;
node(const T &d) :
ndFather(0),
vecSons(),
Data(&d)
{
}
};
#endif
Use -I. before the .cpp files, so that the compiler knows to look for .h files.
g++ -Wall -I. clitest.cpp node.cpp -o clitest
Or just -I:
g++ -Wall -I clitest.cpp node.cpp -o clitest
Related
I'm working on a simple class List, but when compiling the header and cpp file, I get the error: undefined reference to `main'
What am I doing wrong, and how could I fix this?
Here is the list.h file that has simple headers:
list.h
#ifndef LIST_H
#define LIST_H
#include <string>
const int DEFAULT_CAPACITY = 100;
class List
{
public:
List();
List(int capacity);
~List();
void push_back(std::string s);
int size() const;
std::string at(int index) const;
private:
std::string* mData;
int mSize;
int mCapacity;
};
#endif
And here is the list.cpp file:
list.cpp
#include "list.h"
#include <string>
List::List(){
mData = new std::string[DEFAULT_CAPACITY];
mSize = 0;
mCapacity = 100;
};
List::List(int capacity){
mData = new std::string[capacity];
mSize = 0;
mCapacity = capacity;
};
List::~List(){
delete[] mData;
};
void List::push_back(std::string s){
if (mSize<mCapacity){
mData[mSize] = s;
mSize++;
}
};
int List::size() const{
return mSize;
};
std::string List::at(int index) const{
return mData[index];
};
I tried experimenting around with "using namespace std" and how to include , but I can't figure out how to get these errors to go away. What is causing them?
You should be able to compile list.cpp, you can't link it unless you have a main program. (That might be a slight oversimplification.)
The way to compile a source file without linking it depends on what compiler you're using. If you're using g++, the command would be:
g++ -c list.cpp
That will generate an object file containing the machine code for your class. Depending on your compiler and OS, it might be called list.o or list.obj.
If you instead try:
g++ list.cpp
it will assume that you've defined a main function and try to generate an executable, resulting in the error you've seen (because you haven't defined a main function).
At some point, of course, you'll need a program that uses your class. To do that, you'll need another .cpp source file that has a #include "list.h" and a main() function. You can compile that source file and link the resulting object together with the object generated from list.cpp to generate a working executable. With g++, you can do that in one step, for example:
g++ list.cpp main.cpp -o main
You have to have a main function somewhere. It doesn't necessarily have to be in list.cpp. And as a matter of style and code organization, it probably shouldn't be in list.cpp; you might want to be able to use that class from more than one main program.
Undefined reference to main() means that your program lacks a main() function, which is mandatory for all C++ programs. Add this somewhere:
int main()
{
return 0;
}
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
This might be very naive, but I am quite confused about the preprocessor of cpp:
I defined a header file-- Node.h:
#ifndef NODE_H_
#define NODE_H_
#include<iostream>
class Node{
friend std::ostream &operator<<(std::ostream &os, const Node & n);
public:
Node(const int i = -1);
private:
Node * next;
int value;
friend class List;
};
#endif
Then I defined the methods in Node.cpp:
#include "Node.h"
using namespace std;
Node::Node(const int i):value(i), next(NULL){}
ostream& operator <<(ostream & os, const Node& n){
return os<<"value : "<<n.value<<endl;
}
lastly, I have a test.cpp file to check the preprocessor:
#include "Node.h"
//#include <iostream>
using namespace std;
int main(){
Node * n = new Node;
cout<<*n;
}
however, when I tried to compile with gcc, I got the following error:
/home/xuan/lib/singleLinkedList/test.cpp:6:‘Node::Node(int)’undefined reference
Given your files, when I run:
$ g++ test.cpp
/tmp/ccM7wRNZ.o:test.cpp:(.text+0x2c): undefined reference to `Node::Node(int)'
/tmp/ccM7wRNZ.o:test.cpp:(.text+0x44): undefined reference to `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Node const&)'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/bin/ld: /tmp/ccM7wRNZ.o: bad reloc address 0x0 in section `.ctors'
collect2: ld returned 1 exit status
... but if I run:
Simon#R12043 ~/dev/test/cpp
$ g++ test.cpp node.cpp
Simon#R12043 ~/dev/test/cpp
$
Thus, I think you are not including node.cpp among the files to be linked into the project. That is, it is the linker that is not finding the Node class.
I'm working on a simple class List, but when compiling the header and cpp file, I get the error: undefined reference to `main'
What am I doing wrong, and how could I fix this?
Here is the list.h file that has simple headers:
list.h
#ifndef LIST_H
#define LIST_H
#include <string>
const int DEFAULT_CAPACITY = 100;
class List
{
public:
List();
List(int capacity);
~List();
void push_back(std::string s);
int size() const;
std::string at(int index) const;
private:
std::string* mData;
int mSize;
int mCapacity;
};
#endif
And here is the list.cpp file:
list.cpp
#include "list.h"
#include <string>
List::List(){
mData = new std::string[DEFAULT_CAPACITY];
mSize = 0;
mCapacity = 100;
};
List::List(int capacity){
mData = new std::string[capacity];
mSize = 0;
mCapacity = capacity;
};
List::~List(){
delete[] mData;
};
void List::push_back(std::string s){
if (mSize<mCapacity){
mData[mSize] = s;
mSize++;
}
};
int List::size() const{
return mSize;
};
std::string List::at(int index) const{
return mData[index];
};
I tried experimenting around with "using namespace std" and how to include , but I can't figure out how to get these errors to go away. What is causing them?
You should be able to compile list.cpp, you can't link it unless you have a main program. (That might be a slight oversimplification.)
The way to compile a source file without linking it depends on what compiler you're using. If you're using g++, the command would be:
g++ -c list.cpp
That will generate an object file containing the machine code for your class. Depending on your compiler and OS, it might be called list.o or list.obj.
If you instead try:
g++ list.cpp
it will assume that you've defined a main function and try to generate an executable, resulting in the error you've seen (because you haven't defined a main function).
At some point, of course, you'll need a program that uses your class. To do that, you'll need another .cpp source file that has a #include "list.h" and a main() function. You can compile that source file and link the resulting object together with the object generated from list.cpp to generate a working executable. With g++, you can do that in one step, for example:
g++ list.cpp main.cpp -o main
You have to have a main function somewhere. It doesn't necessarily have to be in list.cpp. And as a matter of style and code organization, it probably shouldn't be in list.cpp; you might want to be able to use that class from more than one main program.
Undefined reference to main() means that your program lacks a main() function, which is mandatory for all C++ programs. Add this somewhere:
int main()
{
return 0;
}
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)