For my course, I'm asked to create a Stack class that stores its elements in a STL container (but not the STL stack container).
Requirements:
must be able to store elements of an arbitrary type
every instance accepts insertions as long as the system has enough free memory
must be in namespace cop4530
must use most of the methods and operator overloads shown in header file below
(not back(), +=op, []ops)
methods/functions, etc declared in .h, and implemented in separate .hpp
I then use the stack with another program I create that changes infix notation arithmetic to postfix, and evaluates it if all the elements are comparable.
My professor gave an example header file of what this may look like, which is shown below.
Why does he use a deque pointer??
I've searched and found many cases where people adapt a STL container to a stack, but never an explanation for a STL container as a pointing to a stack. Could someone explain the benefits of this over using a non pointer, if there are any? Examples help
Example .h declaration file
#ifndef COP4530_STACK_H
#define COP4530_STACK_H
#include <iostream>
#include <deque>
namespace cop4530
{
template <typename T>
class Stack;
//----------------------------------
// Stack<T>
//----------------------------------
template <typename T>
class Stack
{
public:
// Constructor, Copy-constructor and destructor
Stack ();
Stack (const Stack<T>&);
Stack (Stack<T> &&);
~Stack ();
// member operators
Stack<T>& operator = (const Stack<T>&);
Stack<T> & operator=(Stack<T> &&);
Stack<T>& operator += (const Stack<T>&);
const T& operator [] (int) const;
T& operator [] (int);
// other methods
int size () const;
int capacity () const;
// Container class protocol
bool empty () const;
void clear ();
void push (const T&);
void push (T &&);
void pop ();
T& top ();
const T& top () const;
T& back ();
// Display methods
void print (std::ostream& os, char ofc = ' ') const;
protected:
std::deque<T> *mystack; // pointer to the stack.
//std::deque<T> mystack; //WHY NOT THIS???
} ;
// operator overloads
template < class T >
std::ostream& operator << (std::ostream& os, const Stack<T>& a);
template < class T >
bool operator == (const Stack<T>&, const Stack<T>&);
template < class T >
bool operator != (const Stack<T>&, const Stack<T>&);
template < class T >
bool operator <= (const Stack<T>&, const Stack<T>&);
#include "stack.hpp"
} // namespace cop4530
#endif
Example .hpp implementation
#ifndef COP4530_STACK_HPP
#define COP4530_STACK_HPP
//----------------------------------------
// Stack<T>:: Implementations
//----------------------------------------
// operator overloads
template <typename T>
std::ostream& operator << (std::ostream& os, const Stack<T>& s)
{
}
template <typename T>
bool operator<=(const Stack<T>& s1, const Stack<T>& s2)
{
}
template <typename T>
bool operator == (const Stack<T>& s1, const Stack<T>& s2)
{
}
template <typename T>
bool operator != (const Stack<T>& s1, const Stack<T>& s2)
{
}
// public methods
template <typename T>
Stack<T>::Stack()
//Constructor
{
}
template <typename T>
Stack<T>::Stack(const Stack<T>& source)
//Copy-constructor
{
}
template <typename T>
Stack<T>::Stack(Stack<T> && source)
{
}
template <typename T>
Stack<T>::~Stack()
// destructor
{
}
template <typename T>
Stack<T>& Stack<T>::operator = (const Stack<T>& source)
// assignment operator
{
}
template <typename T>
Stack<T>& Stack<T>::operator = (Stack<T> && source)
{
}
template <typename T>
Stack<T>& Stack<T>::operator += (const Stack<T>& source)
{
}
template <typename T>
const T& Stack<T>::operator [] (int i) const
// element operator
{
}
template <typename T>
T& Stack<T>::operator [] (int i)
// element operator
{
}
template <typename T>
bool Stack<T>::empty() const
{
}
template <typename T>
int Stack<T>::size() const
{
}
template <typename T>
void Stack<T>::push(const T& Val)
{
}
template <typename T>
void Stack<T>::push(T && Val)
{
}
template <typename T>
void Stack<T>::pop()
{
}
template <typename T>
void Stack<T>::clear()
{
}
template <typename T>
T& Stack<T>::top()
{
}
template <typename T>
const T& Stack<T>::top() const
{
}
template <typename T>
T& Stack<T>::back()
{
}
template <typename T>
void Stack<T>::print(std::ostream& os, char ofc) const
{
}
#endif
Related
I am reading Section 2.4 of the book "C++ tempalte, a complete guide".
I tried to override output operator (<<) as a function template outside the class template Stack<>.
Below is my code, but it doesn't work.
#include <iostream>
#include <string>
#include <vector>
template<class T>
class Stack
{
private:
std::vector<T> v;
public:
void push(T a);
void printOn(std::ostream & os) const;
template <typename U>
friend std::ostream& operator<< (std::ostream& out, const Stack<U> & s);
};
template<typename T>
std::ostream& operator<< (std::ostream out, const Stack<T> & s)
{
s.printOn(out);
return out;
}
template<class T>
void Stack<T>::push(T a)
{
v.push_back(a);
}
template<class T>
void Stack<T>::printOn(std::ostream & out) const
{
for(T const & vi : v)
{out << vi << " ";}
}
int main()
{
Stack<int> s1;
s1.push(12);
s1.push(34);
std::cout << s1;
}
You are just omitting the &, which makes the operator<< inside and outside the class have different function signatures, they are both valid for std::cout << s1, hence the ambiguity
template<typename T>
std::ostream& operator<< (std::ostream& out, const Stack<T> & s)
// ^
{
s.printOn(out);
return out;
}
Well, I'm trying to implement the copy_and_swap idiom on my first Stack in C++, for that I need to create a swap function and this swap function needs to be a friend function, I tried to do it by this way:
template <class T>
class Stack {
private:
int top;
T* a;
int MAX;
public:
Stack(int MAX);
Stack(Stack<T>& s);
bool push(T x);
bool pop();
T peek();
bool isEmpty();
friend void swap(Stack<T>& f, Stack<T>& s);
~Stack();
};
template <class T>
void Stack<T>::swap(Stack<T>& f, Stack<T>& s){
//I will put something where yet.
}
But, the VSCode says this about the swap function: class model "Stack " does not have a "swap" member (I translate for English, my VSCode runs in Portuguese).
How I can do that without receiving this error?
Your friend function is not template, so to define outside, you would have to define the non template function for each type (which seems impracticable):
void swap(Stack<int>& lhs, Stack<int>& rhs){/*..*/}
void swap(Stack<char>& lhs, Stack<char>& rhs){/*..*/}
void swap(Stack<MyType>& lhs, Stack<MyType>& rhs){/*..*/}
Simpler (and better IMO) is to define inside the class.
template <class T>
class Stack {
// ...
friend void swap(Stack& lhs, Stack& rhs) { /*..*/ };
};
Alternative is to make the friend function template:
template <class T> class Stack;
template <class T> void swap(Stack<T>&, Stack<T>&);
template <class T>
class Stack {
// ...
friend void swap<>(Stack& f, Stack& s); // Only the specialization is friend
};
template <class T>
void swap(Stack<T>& lhs, Stack<T>& rhs){ /**/ }
I'm having a problem. I have the template and implementation for a stack in files stack.h and stack.hpp. Then I have an in2out.cpp file that converts infix expressions to outfix expressions and evaluates them. At the beginning of in2out.cpp I "#include stack.h". And inside stack.h (which is my interface) I "#include stack.hpp" (stack.hpp is my implementation). I know this is weird but it's the way I'm required to do it.
Anyways, my problem is, when I'm trying to compile these 3 files together. I get only 1 error which is in stack.h (my interface, listed below). The error is:
In file included from in2post.cpp:7:
stack.h:49: error: expected declaration before â}â token
Line 49 is near the bottom. here is my stack.h file.
#ifndef STACK_H
#define STACK_H
#include <iostream>
#include <vector>
namespace cop4530 {
template<typename T>
class Stack {
private:
std::vector<T> v;
public:
Stack();
~Stack();
Stack (const Stack<T>&);
//Stack (Stack<T>&& );
Stack<T>& operator= (const Stack <T>&);
//Stack<T> & operator=(Stack<T> &&);
bool empty() const;
void clear();
void push(const T& x);
//void push(T && x);
void pop();
T& top();
const T& top() const;
int size() const;
void print(std::ostream& os, char ofc = ' ') const;
};
template<typename T>
std::ostream& operator<< (std::ostream& os, const Stack<T>& a);
template<typename T>
bool operator== (const Stack<T>& a, const Stack <T>& b);
template<typename T>
bool operator!= (const Stack<T>& a, const Stack <T>& b);
template<typename T>
bool operator< (const Stack<T>& a, const Stack <T>& b);
#include "stack.hpp"
} //this is line 49
#endif
Here's my makefile:
CC = g++
FLAGS = -Wall -pedantic
DDD = -g
in2post.x: in2post.cpp stack.h stack.hpp
$(CC) $(FLAGS) $(DDD) -o in2post.x in2post.cpp
EDIT: Here's the beginning of Stack.hpp: (tell me if I should change or add something)
EDIT2: I just decided to include the whole Stack.hpp. Some functions are blanked out cause I didn't need them or couldn't figure them out
#include <iostream>
#include <vector>
template<typename T>
Stack<T>::Stack(){}
template<typename T>
Stack<T>::~Stack(){
v.clear();
}
template<typename T>
Stack<T>::Stack(const Stack<T> & S){
v = S.v;
}
/*
template<typename T>
Stack<T>::Stack(Stack<T> &&){
}
*/
template<typename T>
Stack<T> & Stack<T>::operator=(const Stack<T> & S){
v = S.v;
return *this;
}
/*
template<typename T>
Stack<T>::Stack<T> & Stack<T>::operator=(Stack<T> &&){
}
*/
template<typename T>
bool Stack<T>::empty() const {
return v.empty();
}
template<typename T>
void Stack<T>::clear(){
while (!v.empty())
v.clear();
}
template<typename T>
void Stack<T>::push(const T& x){
v.push_back(x);
}
/*
template<typename T>
void Stack<T>::push(T && x){
}
*/
template<typename T>
void Stack<T>::pop(){
v.pop_back();
}
template<typename T>
T& Stack<T>::top(){
return v[v.size()-1];
}
template<typename T>
const T & Stack<T>::top() const{
return v[0];
}
template<typename T>
int Stack<T>::size() const {
return v.size();
}
template<typename T>
void Stack<T>::print(std::ostream & os, char ofc) const {
for(int i = 0; i < v.size(); i++)
os << v[i] << ofc;
}
/*------------------NON-MEMBER GLOBAL FUNCTIONS-----------------*/
template<typename T>
std::ostream & operator<<(std::ostream & os, const Stack<T> & a) {
a.print(os);
return os;
}
template <typename T>
bool operator==(const Stack<T> & a, const Stack<T> & b) {
if(a.size() != b.size())
return false;
else {
Stack<T> c = a;
Stack<T> d = b;
bool retVal = true;
while(!c.empty()) {
if(c.top() == d.top()) {
c.pop();
d.pop();
}
else {
retVal = false;
break;
}
}
return retVal;
}
}
template <typename T>
bool operator!=(const Stack<T> & a, const Stack<T> & b) {
return !(a == b);
}
template <typename T>
bool operator<(const Stack<T> & a, const Stack<T> & b) {
Stack<T> c = a;
Stack<T> d = b;
bool retVal = true;
while(!c.empty()) {
if(!(c.top() < d.top())) {
retVal = false;
break;
}
else {
c.pop();
d.pop();
}
}
return retVal;
}
Your operator< in stack.hpp has an extra closing curly brace which is closing the namespace early.
I create a template class and want to overload an operator + (several times). I do this in the following way
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
....
template <typename T>
class Polynomial {
....
public:
....
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
friend const Polynomial<T> operator + <> (const Polynomial<T>& poly, const T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
However, I got the following error (which corresponds to the line that begins with 'friend')
problem2.cpp:282:45: error: declaration of ‘operator+’ as non-function
problem2.cpp:282:45: error: expected ‘;’ at end of member declaration
problem2.cpp:282:47: error: expected unqualified-id before ‘<’ token
Following Raxvan's advise, I've changed the code
template class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other);
....
template <typename T>
class Polynomial {
....
public:
....
friend ostream& operator << <> (ostream& out, const Polynomial<T>& other);
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
template <typename NOT_T>
friend const Polynomial<NOT_T> operator +(const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other) {
// implementation
}
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
And in this code I don't have problems with operator << as I had with operator +. Can anyone explain the defference?
The problem is subtle. Your syntax is very close to being
correct. I think your friend declaration should be:
friend Polynominal<T> const operator+<T>( ... );
but both VC++ and g++ accept:
friend Polynominal<> const operator+<T>( ... );
when they can see the declaration:
template <typename T>
const Polynomial<T> operator+(const Polynomial<T>& poly, const T& scalar);
(I can't find anything in the standard to justify this off hand,
but since both VC++ and g++ do it, I suppose that it's something
I've missed.)
And therein lies the problems. The declaration at namespace
scope of operator+ is hidden by the in-class definition. The
compiler complains because the operator+ it finds (the in
class definition) isn't a template itself (although it is
a member of a class template).
If you don't have the problem with operator<<, it's because
you don't have a member function with the same name.
There are several ways of solving this problem. The simplest is
probably to make all of the operator+ friends. Or not: the
most common approach to this is to implement operator+ in
terms of operator+= (which should be a member, in all cases).
In which case, operator+ doesn't have to be a friend.
Or you don't make operator+ a template at all, but definite it
inside your class template:
template <typename T>
class Polynomial
{
friend Polynomial operator+( Polynomial const& lhs, Polynomial const& rhs )
{
// ...
}
friend Polynomial operator+( Polynomial const& lhs, T const& rhs )
{
// ...
}
friend Polynomial operator+( T const& lhs, Polynomial const& rhs )
{
// ...
}
}
(Note that the functions being defined are not templates, but
separate overloaded non-template functions, one for each
instantiation of Polynomial. But the results end up being the
same.)
In this case, you probably would want to have a member function,
called by the operator+ functions, which would do the actual
work; you don't want too much code directly inline like this.
Your operator+ is a function template, to make this a friend, you need to declare it fully including the template parameters, however with a different template parameter, for example:
#include <iostream>
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
Polynomial operator +(const Polynomial& other) const {
std::cout << "inline +" << std::endl;
}
// Here introduce a different type to indicate that this is a template...
template <typename U>
friend const Polynomial<U> operator + (const Polynomial<U>& poly, const U& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
std::cout << "friend +" << std::endl;
}
int main(void)
{
Polynomial<int> f;
f = f + 1;
f = f + 1.; // this fails
f = f + Polynomial<int>();
}
You have to have the same definition when you label a function as friend, this includes the template used above with another type , not T
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
template < class NOT_T> //must respect the deffinition from above
friend const Polynomial<NOT_T> operator + (const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar)
{
//...
}
Edit:
For a simplified explanation i have changed the function to foo and bar to illustrate the difference in declarations:
template <typename T> class Polynomial;
template <typename T>
void bar(const Polynomial<T>& );
void foo(const Polynomial<float> & );//foo for speciffic float
template <typename T>
class Polynomial {
public:
template <typename> //this is also valid declaration;
friend void bar(const Polynomial<T> & );
//it just has to have template because it's a template functions declaration
//not a valid declaration:
//friend void bar <> (const Polynomial<T> & );
//this declaration has no template;
//it refers to a foo function specific to Polynomial<T> type
//so if you use Polynomial<float> there must be a foo for floats
friend void foo(const Polynomial<T> &);
};
template <class T>
void bar(const Polynomial<T>&)
{
}
void foo(const Polynomial<float> &)
{
}
void main()
{
Polynomial<float> pf;
Polynomial<int> pi;
foo(pi);//error since there is not **foo** declared for int
foo(pf);//ok; we have **foo** for Polynomial<float>
bar(pf);
bar(pi);//both ok since bar is templated function;
}
Raxvan.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Undefined symbol on a template operator overloading function
Here are my source code.
In Number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>
using std::istream;
using std::ostream;
template <class T> class Number;
template <class T>
ostream& operator<<(ostream&, const Number<T>&);
template <class T>
istream& operator>>(istream&, Number<T>&);
template <class T>
class Number{
public:
Number(const T &n) :i(n) {}
Number() :i(0) {}
T& operator+(const Number&rhs) const;
T& operator-(const Number&rhs) const;
T& operator*(const Number&rhs) const;
T& operator/(const Number&rhs) const;
friend ostream& operator<< <T> (ostream& , const Number<T>&);
friend istream& operator>> <T> (istream& , Number<T>&);
private:
T i;
};
#endif
And in Number.cpp
#include "Number.h"
template<class T>
T& Number<T>::operator+(const Number&rhs) const
{
return i+rhs.i;
}
template<class T>
T& Number<T>::operator-(const Number&rhs) const
{
return i-rhs.i;
}
template<class T>
T& Number<T>::operator*(const Number&rhs) const
{
return i*rhs.i;
}
template<class T>
T& Number<T>::operator/(const Number&rhs) const
{
return i/rhs.i;
}
template<class T>
ostream& operator<<(ostream&os , const Number<T>&rhs)
{
return os<< rhs.i;
}
template<class T>
istream& operator>>(istream&is , Number<T>&rhs)
{
return is >> rhs.i;
}
I cannot find out why there is
undefined reference to `std::istream& operator>><double>(std::istream&,Number<double>&)'
undefined reference to `Number<double>::operator+(Number<double> const&) const'
errors so on so forth
Use .hpp for template and you can't return reference on a temporary object.
number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>
using std::istream;
using std::ostream;
template <class T> class Number;
template <class T>
ostream& operator<<(ostream&, const Number<T>&);
template <class T>
istream& operator>>(istream&, Number<T>&);
template <class T>
class Number{
public:
Number(const T &n) :i(n) {}
Number() :i(0) {}
T operator+(const Number&rhs) const; // Error Here return T not T&
T operator-(const Number&rhs) const;
T operator*(const Number&rhs) const;
T operator/(const Number&rhs) const;
friend ostream& operator<< <T> (ostream& , const Number<T>&);
friend istream& operator>> <T> (istream& , Number<T>&);
private:
T i;
};
#include <number.hpp>
#endif
number.hpp
#ifndef NUMBER_HPP
#define NUMBER_HPP
template<class T>
T
Number<T>::operator+(const Number& rhs) const
{
return i + rhs.i;
}
template<class T>
T
Number<T>::operator-(const Number&rhs) const
{
return i-rhs.i;
}
template<class T>
T
Number<T>::operator*(const Number&rhs) const
{
return i*rhs.i;
}
template<class T>
T
Number<T>::operator/(const Number&rhs) const
{
return i/rhs.i;
}
template<class T>
ostream& operator<<(ostream&os , const Number<T>&rhs)
{
return os<< rhs.i;
}
template<class T>
istream& operator>>(istream&is , Number<T>&rhs)
{
return is >> rhs.i;
}
#endif
main.cpp
#include <iostream>
#include <number.h>
int
main(int, const char**)
{
Number<double> value(1);
Number<double> add(3);
std::cout << value + add << std::endl;
std::cout << value * add << std::endl;
std::cout << value - add << std::endl;
std::cout << value / add << std::endl;
return 0;
}
The definitions of all those member functions need to be available to any translation unit that instantiates the template. Imagine a file that includes Number.h and attempts to use Number<int>. The compiler then needs to generate all of the code for Number instantiated with T as int. How can it do that if it's only seen Number.h? It doesn't know the definition of the member functions.
The fix is to put the definitions of your member functions (everything from Number.cpp) in Number.h. Alternatively, some people like to name Number.cpp as Number.tpp and, instead of #include "Number.h" in Number.cpp, put #include "Number.tpp" at the bottom of Number.h - basically inverting the inclusion so that the header always includes the implementation.