开发者

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?


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.


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


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.


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜