Thread: overloading the output operator <<

  1. #1
    30 Helens Agree neandrake's Avatar
    Join Date
    Jan 2002
    Posts
    640

    overloading the output operator <<

    I have a stack class which I am supposed to overload the output operator for. The stack class is templated though, and I am getting some errors with the overloaded output.

    Code:
    template <class ELEM, int LIST_SIZE = 10>
    class Stack {
    Code:
    template <class T, int N>
    ostream & operator<< (ostream &disp, Stack<T, N> &rhs)
    {
    	Stack<T, N> temp;
    	while (!rhs.isEmpty())
    	{
    		disp << rhs.topValue() << " ";
    		temp.push(rhs.pop());
    	}
    
    	while (!temp.isEmpty())
    		rhs.push(temp.pop());
    
    	return disp;
    }
    I get linker errors which are very long, but I did some testing and found out that it's because the overloaded operator is templated. If I make two overloaded operator functions, each non-templated but specific to each stack that is used, then it works fine. I've tried changing the template code to
    Code:
    template <class T, int N = 10>
    but you can't use defaults on non-class templates. However, I need to in order to fix the problem. Anyone have any ideas on how to fix this? Is it even possible?
    Environment: OS X, GCC / G++
    Codes: Java, C#, C/C++
    AOL IM: neandrake, Email: neandrake (at) gmail (dot) com

  2. #2
    Registered User
    Join Date
    Dec 2004
    Location
    UK
    Posts
    109
    Code:
    template <class ELEM, int LIST_SIZE = 10>
    I'm not sure if the int LIST_SIZE = 10 is proper c++ at all.

    Why are you trying to pass a default parameter in the template, a numeric papameter at that. Templates are for types.

    Try changing your stack to:
    Code:
    template <class ELEM>
    class Stack {
        
        friend operator<<() // not that your design requires it but it might let you do away with the temporary stack
     
        // blah blah blah
        public:
             Stack(int list_size=10)
             {
                    //blah blah
              }
         // rest of your class
    }
    and your stack to:
    Code:
    template <class T>
    ostream & operator<< (ostream &disp, Stack<T &rhs)
    {
    	Stack<T> temp;
    	while (!rhs.isEmpty())
    	{
    		disp << rhs.topValue() << " ";
    		temp.push(rhs.pop());
    	}
    
    	while (!temp.isEmpty())
    		rhs.push(temp.pop());
    
    	return disp;
    }
    if you make operator<<() a friend of stack you can access the private members of stack and thus avoid using pop() and having to copy the stack around.

  3. #3
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    @sigfriedmcwild: Actually numeric and default values are perfectly allowed for templates. And if you think its only for types then you really need to look at templates some more.
    Edit: Oh and neandrake shouldn't remove the int part of the template because then it changes the type of the object. It may be that a <float,10> can not work with a <float, 9>.

    @neandrake: Does this help?
    Code:
    #include <iostream>
    
    using namespace std;
    
    template <typename T, int Num = 10>
    class Bar
    {
      T x_;
      public:
        Bar(T i) : x_(i) {}
        const T& x() const { return x_; }
    };
    
    template <typename T, int Num>
    ostream& operator<<(ostream& o, const Bar<T,Num> &b)
    {
      return o<<"Num = "<<Num<<" X = "<<b.x()<<endl;
    }
    
    int main()
    {
      Bar<int> bInt(10);
      Bar<float, 20> bFloat(2.2323);
    
      cout<<bInt<<bFloat;
    }
    Last edited by Thantos; 12-07-2004 at 04:29 AM.

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    If the problem is a linker error, then maybe you defined the overloaded operator (or the templated class itself) in a module instead of a header? Templates must be in headers, or else they aren't available.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    30 Helens Agree neandrake's Avatar
    Join Date
    Jan 2002
    Posts
    640
    CornedBee: The overloaded operator is in the same header file as the stack class.
    Thantos: I tried that code, and it works fine, but for some reason mine doesn't. Here is the full stack header file:

    Code:
    #ifndef STACK_H
    #define STACK_H
    
    #include <assert.h>
    #include <iostream>
    using namespace std;
    
    template <class ELEM, int LIST_SIZE = 10>
    class Stack {  
    public:
      Stack():size(LIST_SIZE)
        { clear(); }
      ~Stack()       
        {  }
      void clear()    
        { top = 0; }
      void push(const ELEM& item)   
        { assert(!isFull());  listarray[top++] = item; }
      ELEM pop()   
        { assert(!isEmpty()); return listarray[--top]; }
      ELEM topValue() const 
        { assert(!isEmpty()); return listarray[top-1]; }
      bool isEmpty() const  
        { return top == 0; }
      bool isFull() const  
        { return top == size; }
    private:
      const int size;
      int top; 
    
    
      ELEM listarray[LIST_SIZE];  
      friend ostream & operator<<(ostream &disp, Stack<ELEM, LIST_SIZE> &rhs);
    };
    
    template <class T, int N = 10>
    ostream & operator<< (ostream &disp, Stack<T, N> &rhs)
    {
    	Stack<T, N> temp;
    	while (!rhs.isEmpty())
    	{
    		disp << rhs.topValue() << " ";
    		temp.push(rhs.pop());
    	}
    
    	while (!temp.isEmpty())
    		rhs.push(temp.pop());
    
    	return disp;
    }
    
    #endif
    Note: Only the overloaded operator is my code, I am supposed to implement it.
    Here is the driver that came with it:

    Code:
    #include <iostream>
    using namespace std;
    
    #include "stack.h"
    
    main()
    {
      Stack<int> L1; //default size used
      Stack<char, 6> L2;  //override default size
      
      char v = 'A';
      cout << "Pushing to L2: ";
      while(!L2.isFull()) {
        cout << v << " ";
        L2.push(v);
        v += 1;
      }
      
      cout << "\nStack L2 is: top>>[" << L2 << "]" << endl;
    
      cout << "Popping from L2 to L1: ";
      while(!L2.isEmpty()) {
        L1.push(L2.pop());
        cout << L1.topValue() << " ";
      }
    
      cout << "\nL1's top: " << L1.topValue() << "\n";
      cout << "Stack L1 is...." << L1 << endl;
      L1.clear();
    
      cout << "That is all.\n";
      return 0;
    }
    Environment: OS X, GCC / G++
    Codes: Java, C#, C/C++
    AOL IM: neandrake, Email: neandrake (at) gmail (dot) com

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Note: Only the overloaded operator is my code, I am supposed to implement it.
    Does that mean that everything else came as it is, including the friend declaration of the operator and the shell of the operator (function head line and braces) was supplied? If so, try to compile that, when the operator does nothing but
    return os;

    Also, the function can't have a default template parameter, no matter what.

    What is the long linker error you got?
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Making the following changes worked for me
    Code:
    friend ostream & operator<< <ELEM, LIST_SIZE> (ostream &disp, Stack<ELEM, LIST_SIZE> &rhs);
    and
    Code:
    template <class T, int N>
    ostream & operator<< (ostream &disp, Stack<T, N> &rhs)
    Edit: Oh yeah shoot the instructor:
    Code:
    main()
    change that to
    Code:
    int main()
    CornedBee: The long linker error is probably just listing all the overloaded<< that are currently defined. Personally I find that more annoying then helpful.
    Last edited by Thantos; 12-07-2004 at 08:57 AM.

  8. #8
    30 Helens Agree neandrake's Avatar
    Join Date
    Jan 2002
    Posts
    640
    Thantos:
    Thanks

    Edit: Oh yeah shoot the instructor:
    Yea, he does it alot so much that I no longer think to shoot him anymore.

    The code works, I see the problem now. It was the prototype in the class (not my code) (and the template in front of the operator, but I added that in doubt, hoping it would work). Thanks again.
    Environment: OS X, GCC / G++
    Codes: Java, C#, C/C++
    AOL IM: neandrake, Email: neandrake (at) gmail (dot) com

  9. #9
    Registered User
    Join Date
    Dec 2004
    Location
    UK
    Posts
    109
    Quote Originally Posted by Thantos
    @sigfriedmcwild: Actually numeric and default values are perfectly allowed for templates. And if you think its only for types then you really need to look at templates some more.
    I'm sorry about that. I've never encountered it before and never seen it mentioned anywhere in the, admittedly not so good, c++ books I've read.

    Well you learn something new every day.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The standard library contains the bitset template class which uses a numeric template parameter.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. execl()/fork() output
    By tadams in forum C Programming
    Replies: 19
    Last Post: 02-04-2009, 03:29 PM
  2. Overloading operator++
    By vopo in forum C++ Programming
    Replies: 9
    Last Post: 08-18-2008, 02:52 AM
  3. Replies: 4
    Last Post: 11-30-2005, 04:44 PM
  4. Formatting output into even columns?
    By Uncle Rico in forum C Programming
    Replies: 2
    Last Post: 08-16-2005, 05:10 PM
  5. Output problems with structures
    By Gkitty in forum C Programming
    Replies: 1
    Last Post: 12-16-2002, 05:27 AM