views:

441

answers:

7

Is there a standard way to access the underlying container of stack, queue, priority_queue ?

I found a method called : _Get_container() in VS2008 implementation of stack and queue, but no one for priority_queue! I think it is not standard anyway.

Also, I know it is a silly question! where can I find official documentation of the standard library ?


Just for clarification, I wasn't trying to mess up with the underlying container. All what I was trying to do is this :

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

    outputstream << "[";

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

    outputstream << " ]";

    return outputstream;
}

// stack, queue
template
    < class Type
    , template<class Type, class Container = std::deque<Type> > class Adapter
    >
std::ostream& operator<<(std::ostream& outputstream, const Adapter<Type>& adapter)
{
    return printOneValueContainer(outputstream, adapter._Get_container());
}
.
.
.
std::stack<int> iStack;
.
.
std::cout << iStack << std::endl;

I hope you see that _Get_container() is not standard, and there is no one for priority_queue in VS2008 implementation.

+3  A: 

No, there is no standard way of doing that. As for access to the standard, it is not available onn the web, you have to buy a copy! However, there are various copies of drafts available here.

anon
Thanx Neil, I think I'll buy the documentation :)
AraK
+1  A: 

I certainly hope there isn't a way to access the underlying container of a priority queue. If you could then you could mess up the internal heap structure of the priority queue. In any case the point of those adaptors is that they only present you with the minimal interface of the stack or queue, and abstract out all the other things. So if you needed to use any other features, you should have used the original container directly.

As for documentation of the STL, you can look at the documentation of SGI's STL here. There are a few differences between SGI's STL and the one in the C++ standard, but they are mostly noted on that site. Also, cppreference.com is a wiki documentation of the C++ library that is becoming more complete.

newacct
I see your point. What I am trying to do is writing a generic function that streams the contents of the stack, queue and priority_queue. It is just for fun so no problem :)
AraK
A: 

This SGI page is the most "official" documentation available online, I believe.

The reason that you can't get direct access to the underlying container is that the adapter changes the usage pattern, and having the methods of the underlying container available would violate that new usage pattern. For example:

[2] This restriction is the only reason for queue to exist at all. Any container that is both a front insertion sequence and a back insertion sequence can be used as a queue; deque, for example, has member functions front, back, push_front, push_back, pop_front, and pop_back The only reason to use the container adaptor queue instead of the container deque is to make it clear that you are performing only queue operations, and no other operations. http://www.sgi.com/tech/stl/queue.html

If you want to get around this design feature, you can do something like:

template <typename T>
class clearable_queue : public std::queue<T>
{
public:
    void clear() { c.clear(); }
};
Tim Sylvester
Usually you should compose containers rather than derive from them. They don't have virtual destructors, for example.
GMan
Agreed. However in this case we don't care about destructors, and by using inheritance we avoid having to define the `queue` interface as proxy methods.
Tim Sylvester
+1  A: 

As a general rule, any identifier that starts with an underscore is a vendor-specific extension or an implementation detail. So _Get_container() is just an addition made by Microsoft because it simplified their implementation. It is not intended to be used.

As for where to find the documentation, it's split into several parts.

The authoritative source is, of course, the language standard. As Neil Butterworth said, there are draft copies available for free online (which are still very useful. The differences from those to the final version are really minimal). Alternatively, you can buy a copy. It should be available from whichever organization represents ISO in your country (and probably from a bajillion other sources as well). The document you're looking for is ISO/IEC 14882:2003 Programming Language C++. (14882 is the standard number. 2003 is the year of the last revision. If you come across the 1998 version, you can use that too. The differences are really ridiculously small between the two, and basically just amounts to a few clarifications. It's probably best to stay away from the drafts for C++0x, as the changes there are far more extensive)

Apart from that, every implementation of the standard library is required to document a large number of details (implementation-defined behavior, things which are not specified in the standard, but is left up to the library implementer). And in addition, most of them also put up a detailed documentation of the entire library as well.

Microsoft has detailed documentation available on MSDN. The documentation respects the standard, and clearly marks all nonstandard extensions so you know which is which.

SGI also has the documentation online (although it is older and in some cases, not entirely accurate).

IBM has similar documentation available on their website, and I believe GCC does too.

jalf
Thanks jalf that was helpful :)
AraK
Oh, didn't even realize this was your question. Thought you knew this stuff already. ;)
jalf
A: 

The C++ standard is available in hardcover, ISBN 0470846747.

MSalters
+1  A: 

I mentioned it in a comment, but after some thinking it seems to be an OK solution. queue/stack/priority_queue (that is, all of the adapter classes) all have a protected member c which is the underlying container (see ISO/IEC 14882:2003 section 23.2.2.4), so if you inherit from any of these, you can access it directly.

I know the typical wisdom is to not inherit from STL containers due to non-virtual dtors, but this case is an exception. The goal is not to overload functionality, but to make minor extensions to the interface of the adapter. Here is an example of adding the ability to access the underlying container.

#include <queue>
#include <iostream>

template <class Container>
class Adapter : public Container {
public:
    typedef typename Container::container_type container_type;
    container_type &get_container() { return this->c; }
};

int main() {
    typedef std::queue<int> C;
    typedef Adapter<C> Container;

    Container adapter;

    for(int i = 0; i < 10; ++i) {
     adapter.push(i);
    }

    Container::container_type &c = adapter.get_container();
    for(Container::container_type::iterator it = c.begin(); it != c.end(); ++it) {
     std::cout << *it << std::endl;
    }
}

Unfortunately, you'll have to resort to type-punning to "upgrade" an existing std::queue<int> * to a Adapter<std::queue<int> > * without type punning. Technically, this would likely work fine... but I recommend against it:

    typedef std::stack<int> C;
    typedef Adapter<C> Container;
    C stack;
    // put stuff in stack
    Container *adapter = reinterpret_cast<Container *>(&stack);
    Container::container_type &c = adapter->get_container();
    // from here, same as above

So I would recommend using typedefs to make it easy to swap between the two. (Also notice in my example that you only need to change 1 line to change it from a queue to a stack because of liberal use of typedefs).

Evan Teran
+2  A: 

I spotted the following solution somewhere on the web and I'm using it in my projects:

template <class T, class S, class C>
    S& Container(priority_queue<T, S, C>& q) {
        struct HackedQueue : private priority_queue<T, S, C> {
            static S& Container(priority_queue<T, S, C>& q) {
                return q.*&HackedQueue::c;
            }
        };
    return HackedQueue::Container(q);
}

int main()
{
    priority_queue<SomeClass> pq;
    vector<SomeClass> &tasks = Container(pq);
    return 0;
}

Have fun :).

galaxy
I like this hack man. Thanks ;)
AraK