Alcott
Alcott

Reputation: 18585

overload operator<< for std::stack

Code goes first:

//.cpp file

template <typename T>
ostream &operator<<(ostream &os, stack<T> &st)
{
    while(! st.empty()) {
        os << st.top() << " ";
        st.pop();
    }
    return os;
}

template <typename T>
void stack_sorter(stack<T> &st)
{
    cout << st << endl;  //no output, st is empty?
    //...
}

int main()
{
    stack<int> s;
    s.push(4);
    s.push(3);
    s.push(5);
    cout << s << endl;  //ok
    stack_sorter(s);
}

output:

5 3 4  //this was the output in main, not in stack_sorter
       //empty line, but s is not empty, why?

Question:

As what I did in main, I pass s to stack_soter(), but I got no output in stack_sorter(). What's wrong?

Upvotes: 1

Views: 134

Answers (4)

Potatoswatter
Potatoswatter

Reputation: 137910

As others have pointed out, pop_back makes your output operation destructive. There is simply no way to read the contents of a stack without emptying it… that's the nature of a pure stack.

Also, it is very poor practice to overload operators for standard types. Because of the way name lookup works (ADL, that is, the way the language finds the overload function to call), it overload functions are supposed to be in the same namespace as the types they overload for. Since you can't put the function in std::, the next best alternative is the global namespace, which then pollutes that.

But the problem is solvable! Fortunately, stack provides for inheritance. The underlying container is accessible to derived classes and it is named c.

template< typename value_arg, typename container_arg = std::deque< value_arg > >
struct printable_stack : std::stack< value_arg, container_arg > {

    // provide constructors :v( . This is better supported in C++11.
    printable_stack( container_arg const &in = container_arg() )
        : std::stack< value_arg, container_arg >( in ) {}

    friend std::ostream &operator<<
                            ( std::ostream &s, printable_stack const &o ) {
        for ( typename container_arg::iterator i = this->c.begin();
                                               i != this->c.end(); ++ i ) {
            s << * i << ' ';
        }
    }
};

Also, having a dedicated class allows you to provide an extra member to hold the separator string, so it can be something besides a simple space character.

Upvotes: 2

Nicola Musatti
Nicola Musatti

Reputation: 18226

Your call to st.pop() in the loop in your ostream &operator<<(ostream &os, stack<T> &st) empties the stack.

Upvotes: 1

Me again
Me again

Reputation: 541

template <typename T>
ostream &operator<<(ostream &os, stack<T> st) //not &st
{
    while(! st.empty()) {
        os << st.top() << " ";
        st.pop();
}
return os;
}

Upvotes: 3

king_nak
king_nak

Reputation: 11513

In your operator <<, you pop all values to output them. So after cout << s << endl;, your stack is emptied!

One possibility is to not pass by reference, but a copy of the stack. However, this will also copy all objects in it.

Upvotes: 5

Related Questions