Reputation: 13
I am executing a C++ program on my Xcode 6.2, but I am getting this error :
Undefined symbols for architecture x86_64:
"operator+(Stack1<int> const&, Stack1<int> const&)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am not sure how to go ahead in resolving this issue, I checked few others on Stackoverflow.com but could not resolve my issue ,
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Stack1;
template <class T>
Stack1<T> & operator+(const Stack1<T> &x, const Stack1<T> &y) {
Stack1<T> z = x;
for (unsigned int i=x.size(); i<(x.size()+y.size()); i++) {
z.push(y[i]);
}
return z;
}
template <class T>
class Stack1 {
friend Stack1<T> & operator+(const Stack1<T> &x, const Stack1<T> &y);
private: vector <T> elems;
public: bool empty();
void push(const T &item);
T & top();
void pop();
long size();
};
template <class T>
bool Stack1<T>::empty() {
return elems.empty();
}
template <class T>
void Stack1<T>::push(const T &item){
elems.push_back(item);
}
template <class T>
T &Stack1<T>::top(){
return elems.back();
}
template <class T>
void Stack1<T>::pop() {
if (!elems.empty())
return elems.pop_back();
}
template <class T>
long Stack1<T>::size() {
return elems.size();
}
int main(int argc, const char * argv[]) {
Stack1 <int> intStack;
Stack1 <float> floatStack;
Stack1 <string> stringStack;
Stack1 <int> a;
Stack1 <int> b;
intStack.push(7);
intStack.push(3);
intStack.push(0);
intStack.push(8);
floatStack.push(0.9);
floatStack.push(4.78);
floatStack.push(2.157);
stringStack.push("test1");
stringStack.push("abc");
while (!intStack.empty()) {
cout << "Popping from intStack: " << intStack.top() << endl;
intStack.pop();
}
if (intStack.empty()) {
cout << "intStack is empty" << endl;
}
while (!floatStack.empty()) {
cout << "Popping from intStack: " << floatStack.top() << endl;
floatStack.pop();
}
if (floatStack.empty()) {
cout << "floatStack is empty" << endl;
}
while (!stringStack.empty()) {
cout << "Popping from intStack: " << stringStack.top() << endl;
stringStack.pop();
}
if (stringStack.empty()) {
cout << "stringStack is empty" << endl;
}
for (int i=0; i<3; i++) {
a.push(i);
}
for (int i=9; i>5; i--) {
b.push(i);
}
// cout << "Size of a:" << a.size();
Stack1 <int> c;
c = a+b;
while (!c.empty()) {
cout << "Popping from c: " << c.top() << endl;
c.pop();
}
return 0;
}
Get this error:
error: failed to launch '/Users/User-name/Library/Developer/Xcode/DerivedData/4_TemplatedStack-bmcfhzdrgyhhybajmxvpyuypgmag/Build/Products/Debug/4_TemplatedStack'
Upvotes: 0
Views: 907
Reputation: 3260
There are several problems here for your definition of function for operator +
,
You are defining here
template <class T>
Stack1<T> & operator+(const Stack1<T> &x, const Stack1<T> &y)
saying
operator+
is a template function, but in your class definition of Stack1
, you are saying
friend Stack1<T> & operator+(const Stack1<T> &x, const Stack1<T> &y);
is not a template function, this is the cause of the link error. The solution is inside Stack1
changing to
friend Stack1<T> operator+ <>(const Stack1<T> &x, const Stack1<T> &y);
,
the detailed explanation is here in isocpp FAQ.
Notice that you are returning reference Stack1<T> & operator+
, but inside the function body you have return z
, where z
is an local variable, as soon as the function call is finished, z
is destroyed, a reference to that will be catastrophic.
you need to change
for(unsigned int i=x.size(); i<(x.size()+y.size()); i++)
to
for(unsigned int i=0; i<y.size(); i++)
since you are pushing y[i]
and i
can not be greater than y.size()
.
You also need to overload operator []
for your class Stack1
.
Upvotes: 0
Reputation: 95439
To add to the other answers, because of the way that templates and template instantiation work, it generally does not make sense to define and declare templates separately, since your definition would need to go in the header file anyway in order to allow it to be instantiated. Normally, the declaration and the definition are kept separate so that the declaration goes in the header file, while the definition is in a source file which provides two benefits: 1.) users of the library only need the header and the compiled source, so keeping them separate allows for speedier development (by using the pre-compiled library) 2.) outside of opensource, the implementation code may sometimes be hidden so that only the header is distributed. When it comes to templates, however, both the definition and declaration are necessary in order to instantiate the template. Because of this, you'll save yourself quite a bit of boilerplate and syntactic annoyance by simply combining the declaration and definition together like so:
// stack1.h
#ifndef STACK1_H
#define STACK1_H
#include <vector>
template<typename T> class Stack1 {
public:
Stack1() {}
Stack1(const Stack1& o) : elements_(o.elements_) {}
Stack1(const std::vector<T>& elements) : elements_(elements) {}
virtual ~Stack1() {}
Stack1 operator+(const Stack1& o) const {
return Stack1(elements_ + o.elements_);
}
void push(const T& item) { elements_.push_back(item); }
bool empty() const { return elements_.empty(); }
T top() const { return elements_.back(); }
size_t size() const { return elements_.size(); }
private:
std::vector<T> elements_;
};
#endif
Although, it is possible to specify the definition syntax correctly for templates when the definition and declaration are separated, it is much easier to do it this way. If you do continue to separate the definition and declaration, in addition to the other suggestions, you'll want to use the "inline" keyword for your definitions in order to prevent one-definition-rule violations if you put the definitions in a header (as needed for using the template from multiple source files).
Upvotes: 0
Reputation: 36
The issue mentioned in the comments refers to a dangerous bug in your code, but has nothing to do with the linker issue. What you need to do is add <>
after operator+
:
friend Stack1<T> & operator+ <>(const Stack1<T> &x, const Stack1<T> &y);
Then, long size()
needs to be const
if you want it to be called on const
objects.
Anyways. please read this guide on operator overloading. operator+
should not return a reference, especially to a local variable. If anything, its return value should be const T
. There are other issues but I leave that as an exercise to you.
Upvotes: 1