Qiang Li
Qiang Li

Reputation: 10855

How to print out all elements in a std::stack or std::queue conveniently?

If I do not to want to create a new container in order to do so?

Upvotes: 20

Views: 90619

Answers (9)

joao
joao

Reputation: 3566

You could use the answer here: https://stackoverflow.com/a/29325258/177259 to make a simple get_container which exposes the underlying protected member holding the underlying container of the std::stack container adapter.

Uses bit of hackery, admittedly, but it should work. I've modified it so it returns a const ref to the inner container.

Then you can easily iterate the stack's (or any other container adapter) inner container:

#include <iostream>
#include <stack>
#include <vector>

template <class Adapter>
const typename Adapter::container_type & get_container (Adapter &a)
{
    struct hack : Adapter {
        static typename Adapter::container_type & get (Adapter &a) {
            return a.*&hack::c; // access protected member variable
        }
    };
    return hack::get(a);
}

int main () { 
    std::deque<int> inner{1, 2, 3};
    std::stack<int> s{inner};

    // for (auto x : s) std::cout << x << " "; // not allowed
    for (auto x : get_container(s)) std::cout << x << " ";
    // for (auto& x : get_container(s)) x = 42; // not allowed, thankfully
}

Upvotes: 0

user2376997
user2376997

Reputation: 511

Try this:

template<typename T, typename C>
struct myStack : std::stack<T, C> {
    typedef std::stack<T, C> Stack;
    using Stack::stack;
    using Stack::c;                   
};

int main() 
{
    myStack<int, std::deque<int>> s;
    s.push(1);
    s.push(2);

    std::deque<int>::iterator it = s.c.begin();
    while (it != s.c.end())
        std::cout << ' ' << *it++;
}

Here we expose underlying container of std::stack as member c.

Upvotes: 1

baziorek
baziorek

Reputation: 2684

I've found solution which should work with all implementations (IMO) of std::stack, but unfortunately the stack must use std::vector instead of queue.

template<typename T>
void printStack(const std::stack<T, std::vector<T>>& s)
{
    typedef typename std::stack<T>::const_reference EntryTypeRef;
    typedef std::remove_reference_t<EntryTypeRef> EntryType;

    for(size_t i=0; i < s.size(); ++i)
    {
        EntryType* e = &s.top();
        cout << *(e-i) << endl;
    }
}

std::vector is dynamic array, so we can use pointer arytmetics.

The marked answer to the question assumes, that the stack has field named 'c', I have another solution which would work with std::stack implementation which has container as first field, but its name does not matter:

template<typename T>
void printStack(const std::stack<T>& s)
{
    typedef typename std::stack<T>::container_type Container;

    const auto containerPtr = reinterpret_cast<const Container*>(&s);

    for(auto e : *containerPtr)
        cout << e << endl;
}

Upvotes: 1

joshbodily
joshbodily

Reputation: 1093

Posting b/c I found this useful for debugging. Pop from original into a temp and then pop from temp back into original:

template <typename T>
void dump_stack(std::stack<T>& stack) {
  std::stack<T> temp;
  while (!stack.empty()) {
    T top = stack.top(); stack.pop();
    std::cout << top << " ";
    temp.push(top);
  }
  while (!temp.empty()) {
    T top = temp.top(); temp.pop();
    stack.push(top);
  }
}

Upvotes: 2

Sam
Sam

Reputation: 61

ostream & operator<<(ostream & os, stack<double> my_stack) //function header
{
    while(!my_stack.empty()) //body
    {
        os << my_stack.top() << " ";
        my_stack.pop();
    }
    return os; // end of function
}


/*
using this simple overloaded operator function, you're able to print out all the components of a stack by doing a simple cout << your_stack_name;*/

Upvotes: 6

Tariq Ayman
Tariq Ayman

Reputation: 73

It can be easily done using recursion you just need to know when to re-add the next element

For Stack

void print(stack<char> &s)
{
    if(s.empty())
    {
        cout << endl;
        return;
    }
    char x= s.top();
    s.pop();
    print(s);
    s.push(x);
    cout << x << " ";
 }

And this one is For Queue

void print(queue<char> &s,int num)
{
    if(!num)
    {
        cout << endl;
        return;
    }
    char x= s.front();
    s.pop();
    cout << x << " ";
    s.push(x);
    print(s,--num);
}

Good Luck

Upvotes: 2

Khaled Alshaya
Khaled Alshaya

Reputation: 96849

I've written a snippet to do that for debugging. For example:

std::stack<int> s; // works with std::queue also!
s.push(1);
s.push(2);

std::cout << s; // [ 1, 2 ]

Please forgive me for this hackish code! but this is what I've written months ago:

#include <stack>
#include <queue>
#include <ostream>

template <class Container, class Stream>
Stream& printOneValueContainer
    (Stream& outputstream, const Container& container)
{
    typename Container::const_iterator beg = container.begin();

    outputstream << "[";

    while(beg != container.end())
    {
        outputstream << " " << *beg++;
    }

    outputstream << " ]";

    return outputstream;
}

template < class Type, class Container >
const Container& container
    (const std::stack<Type, Container>& stack)
{
    struct HackedStack : private std::stack<Type, Container>
    {
        static const Container& container
            (const std::stack<Type, Container>& stack)
        {
            return stack.*&HackedStack::c;
        }
    };

    return HackedStack::container(stack);
}

template < class Type, class Container >
const Container& container
    (const std::queue<Type, Container>& queue)
{
    struct HackedQueue : private std::queue<Type, Container>
    {
        static const Container& container
            (const std::queue<Type, Container>& queue)
        {
            return queue.*&HackedQueue::c;
        }
    };

    return HackedQueue::container(queue);
}

template
    < class Type
    , template <class Type, class Container = std::deque<Type> > class Adapter
    , class Stream
    >
Stream& operator<<
    (Stream& outputstream, const Adapter<Type>& adapter)
{
    return printOneValueContainer(outputstream, container(adapter));
}

You can stream std::stack and std::queue just like any other supported type!

Upvotes: 16

Etienne de Martel
Etienne de Martel

Reputation: 36852

You can't iterate through a stack or a queue. In fact, SGI's documentation says this (it's about stack, but it's the same reason for queue):

This restriction is the only reason for stack to exist at all. Note that any Front Insertion Sequence or Back Insertion Sequence can be used as a stack; in the case of vector, for example, the stack operations are the member functions back, push_back, and pop_back. The only reason to use the container adaptor stack instead is to make it clear that you are performing only stack operations, and no other operations.

So, if you really want to do this, you'll have to empty the stack (or queue):

std::stack<Whatever> s;
// ...
while(!s.empty())
{
    Whatever w = s.top();
    std::cout << w;
    s.pop();
}

Upvotes: 11

Benjamin Lindley
Benjamin Lindley

Reputation: 103693

  1. If you need to do this, then stack or queue is not the correct choice of container.
  2. If you still insist on doing this, the best way is to make a copy and pop elements off of it and print them. I'm not going to suggest another way because there's no point.

Upvotes: 0

Related Questions