std::stack
provides an intentional restriction of the functionality of the wrapped container.
For the cases where you still need to e.g. iterate through the container's elements, std::stack
provides the wrapped container as a protected
member c
.
protected
means that you need to define a derived class in order to access it without using really low level tricks. The code below might still be regarded as pretty low level, but it does not have any casts, no explicit conversions. I think that's nice, in a way, although it's just an exploitation of loophole in the C++ type system.
#include <stack>
#include <iostream>
using namespace std;
template< class Item >
struct Hack
: stack<Item>
{
static
auto container_of( stack<Item> const& st )
-> typename stack<Item>::container_type const&
{ return st.*(&Hack::c); }
};
namespace std
{
template< class Item >
auto begin( stack<Item> const& s )
-> decltype( Hack<Item>::container_of( s ).begin() )
{ return Hack<Item>::container_of( s ).begin(); }
template< class Item >
auto end( stack<Item> const& s )
-> decltype( Hack<Item>::container_of( s ).end() )
{ return Hack<Item>::container_of( s ).end(); }
}
auto main()
-> int
{
stack<int> s;
s.push(1);
s.push(2);
for( int const v : s ) { cout << v << endl; }
}
The advantage of the hack is that it can be used wherever you need to iterate through the items of a std::stack
, e.g. for purposes of debugging.
But for ordinary programming I would instead derive my own stack from std::stack
, and I guess that's the original intent.
That can go like this:
#include <stack>
#include <iostream>
using namespace std;
template< class Item >
class Stack
: public std::stack<Item>
{
protected:
using std::stack<Item>::c;
public:
auto begin() const -> decltype( c.cbegin() ) { return c.cbegin(); }
auto end() const -> decltype( c.cend() ) { return c.cend(); }
};
auto main()
-> int
{
Stack<int> s;
s.push(1);
s.push(2);
for( int const v : s ) { cout << v << endl; }
}