重载运算符<<用于 std::stack

overload operator<< for std::stack

本文关键字:lt stack 运算符 用于 重载 std      更新时间:2023-10-16

代码优先:

//. cpp文件
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);
}
输出:

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

问题:

和我在main中所做的一样,我将s传递给stack_soter(),但是在stack_sorter()中没有得到输出。怎么了?

在您的operator <<中,您弹出所有值以输出它们。所以在cout << s << endl;之后,你的堆栈被清空!

一种可能是不通过引用传递,而是通过堆栈的副本传递。但是,这也会复制其中的所有对象。

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

正如其他人指出的那样,pop_back使您的输出操作具有破坏性。没有办法读取堆栈的内容而不清空它,这就是纯堆栈的本质。

同样,为标准类型重载操作符也是非常糟糕的做法。由于名称查找的工作方式(ADL,即语言查找要调用的重载函数的方式),它的重载函数应该与它们重载的类型在同一个名称空间中。由于不能将函数放在std::中,所以下一个最佳选择是全局命名空间,但这会对全局命名空间造成污染。

但是这个问题是可以解决的!幸运的是,stack提供了继承。底层容器可以被派生类访问,它被命名为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 << ' ';
        }
    }
};

另外,有一个专用的类允许您提供一个额外的成员来保存分隔符字符串,所以它可以是一个简单的空格字符以外的东西。

ostream &operator<<(ostream &os, stack<T> &st)的循环中调用st.pop()将清空堆栈