0

I am trying to loop through a stack in C++ 11, however, the following code seems not valid, i can loop through vector in this way, why stack won't work here?

#include <stack>
#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
    stack<int> s;
    s.push(1);
    s.push(2);
    for (int val:s){
        cout<<val<<endl;
    }
    return 0;
}
J.W.
  • 17,991
  • 7
  • 43
  • 76
  • possible duplicate of [Does std::stack expose iterators?](http://stackoverflow.com/questions/525365/does-stdstack-expose-iterators) – DanielKO Mar 22 '14 at 07:42

6 Answers6

5

std::stack is not a container (not in the same sense that std::vector is). It is a container adaptor. It intentionally limits the functionality of the underlying container to support only stack operations. One of the things it doesn't have is iterators, and no begin or end member functions, which are required for the range-for loop to work. A stack is not meant to be iterated over. If you want to iterate over the collection, then you don't want a stack. You want a sequence container, such as std::vector or std::deque.

If you want something with functionality which is some kind of hybrid of a sequence container and a stack, (e.g. something that supports iteration, but insertion and removal is only allowed on one end), then you'll have to implement that yourself.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
1

Because stack does not have iterators nor does it have begin and end. If you need stack with iterators, you'll need to implement it yourself on top of other container (std::list, std::vector, etc).

Claudiordgz
  • 3,023
  • 1
  • 21
  • 48
1

std::stack does not provide a begin or end member function so it can not work with a range based for loop which requires both which we can see from cppreference's entry for range-based for loop which tells that it expands to:

{
 auto && __range = range_expression ;
 for (auto __begin = begin_expr,
            __end = end_expr;
        __begin != __end; ++__begin) {
    range_declaration = *__begin;
    loop_statement
 }
} 

and:

If __range's type is a class type with either or both a begin or an end member function, then begin_expr is __range.begin() and end_expr is __range.end();

or:

Otherwise, begin_expr is begin(__range) and end_expr is end(__range), which are found via argument-dependent lookup with std as an associated namespace.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
1

This is a duplicate question; see Does std::stack expose iterators? for the answer -- std::stack does not have iterators.

Community
  • 1
  • 1
dbeachy1
  • 179
  • 1
  • 3
  • 12
  • Fair points. To summarize, since std:stack doesn't have built-in iterators I use a different container that does support iterators when I need to iterate, such as an std::vector or std::list. std::vector doc is [here](http://www.cplusplus.com/reference/vector/vector/) and std::list doc is [here](http://www.cplusplus.com/reference/list/list/). I prefer using std::vector since it performs better than std::list when iterating sequentially or adding/removing items from the end. – dbeachy1 Apr 14 '14 at 16:28
1

The range based loop produces code similar to the following: (Source)

//__begin, __end,__range has been used for explanation only.
{
auto && __range = range_expression ; 
for (auto __begin = begin_expr,
    __end = end_expr; 
    __begin != __end; ++__begin) {

    range_declaration = *__begin; 
    loop_statement 

    } 
} 

As you can see it uses begin and end iterators underneath. It is only valid for the types which have begin() and end() methods defined which is not the case for stack.

vaibhav kumar
  • 885
  • 1
  • 11
  • 13
1

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; }
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • You managed to shove `auto` everywhere except the only place where it would help (range-based for loops). Also shoving new functions into `std` is a big NO NO. – DanielKO Mar 22 '14 at 07:41
  • @DanielKO: re the no new functions, no the functions aren't new, and no the rule isn't as general as you write. but the specializations shown in the first in the answer (hence description of it as a hack) do not depend on a user defined type. if they had depended on a user-defined type they would, with one common interpretation of the standard (its use of the word "specialization"), would have have been OK, but otherwise it's Undefined Behavior. in C++11 by §17.2.6.4.2.1/1. that's the kind of stuff that hacks involve. i would always choose to show it, than to leave people *uninformed*. – Cheers and hth. - Alf Mar 22 '14 at 11:00