有没有办法访问STL容器适配器的底层容器?

时间:2009-07-26 18:49:37

标签: c++ data-structures stl standards

是否有 标准 方式来访问stackqueuepriority_queue的基础容器?

我在_Get_container()VS2008的{​​{1}}实现中找到了一个名为stack的方法,但queue没有人!我认为无论如何它都不是标准的。

另外,我知道这是一个愚蠢的问题!我在哪里可以找到标准库的官方文档?


为了澄清,我并没有试图搞砸底层容器。我试图做的就是:

priority_queue

我希望您看到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; 不是标准的,_Get_container()实施priority_queue中没有{。}}。

10 个答案:

答案 0 :(得分:18)

我在网络上的某个地方发现了以下解决方案,我在我的项目中使用它:

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;
}

玩得开心:)。

答案 1 :(得分:8)

我在评论中提到过,但经过一番思考后似乎是一个很好的解决方案。 queue / stack / priority_queue(即所有适配器类)都有一个protected成员c,它是底层容器(参见ISO / IEC 14882:2003第23.2.2.4节),因此,如果您继承任何这些,您可以直接访问它。

我知道典型的智慧是不会因为非虚拟dtors而继承STL容器,但这种情况是个例外。目标不是重载功能,而是对适配器的接口进行小的扩展。以下是添加访问基础容器的功能的示例。

#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;
    }
}

不幸的是,您不得不诉诸类型惩罚来将现有的std::queue<int> *“升级”为Adapter<std::queue<int> > *而不会出现类型惩罚。从技术上讲,这可能会很好......但我建议不要这样做:

    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        

所以我建议使用typedef,以便在两者之间轻松切换。 (另请注意,在我的示例中,由于queue s的自由使用,您只需更改1行即可将其从stack更改为typedef

答案 2 :(得分:8)

基于accepted answer,更通用的方法:

template <class ADAPTER>
typename ADAPTER::container_type & get_container (ADAPTER &a)
{
    struct hack : ADAPTER {
        static typename ADAPTER::container_type & get (ADAPTER &a) {
            return a.*&hack::c;
        }
    };
    return hack::get(a);
}

我从this answer了解到,.*&实际上是两个运算符,其中&hack::c(类型为ADAPTER::container_type ADAPTER::*)的指针是目标或{{ 1}}运算符来检索底层容器本身。 .*可以访问受保护的成员,但在获得指针后,保护将丢失。因此允许hack

答案 3 :(得分:3)

不,没有标准的方法可以做到这一点。至于访问标准,它不在网上,你必须购买一份!但是,有各种草稿副本 available here

答案 4 :(得分:3)

This SGI page是在线提供的最“官方”文档,我相信。

您无法直接访问底层容器的原因是适配器更改了使用模式,并且使基础容器的方法可用会违反该新的使用模式。例如:

  

2此限制是队列完全存在的唯一原因。任何前插入序列和后插入序列的容器都可以用作队列;例如,deque具有成员函数front,back,push_front,push_back,pop_front和pop_back使用容器适配器队列而不是容器双端队列的唯一原因是要明确表示您只执行队列操作,而没有其他操作。   http://www.sgi.com/tech/stl/queue.html

如果您想绕过此设计功能,可以执行以下操作:

template <typename T>
class clearable_queue : public std::queue<T>
{
public:
    void clear() { c.clear(); }
};

答案 5 :(得分:2)

作为一般规则,以下划线开头的任何标识符都是特定于供应商的扩展或实现细节。所以_Get_container()只是微软的一个补充,因为它简化了它们的实现。它无意使用。

至于在何处查找文档,它分为几个部分。

权威来源当然是语言标准。正如Neil Butterworth所说,有免费的在线草稿(这些副本仍然非常有用。与最终版本的差异非常小)。或者,您可以购买一份副本。它应该来自您所在国家/地区代表ISO的任何组织(也可能来自其他来源)。您要查找的文件是ISO/IEC 14882:2003 Programming Language C++。 (14882是标准编号.2003是最后修订版的年份。如果你遇到1998版本,你也可以使用它。两者之间的差异非常小,基本上仅仅是一些澄清。它是可能最好远离C ++ 0x的草稿,因为那里的变化要广泛得多)

除此之外,标准库的每个实现都需要记录大量细节(实现定义的行为,标准中未指定的内容,但由库实现者决定)。此外,他们中的大多数也提供了整个图书馆的详细文档。

Microsoft在MSDN上提供了详细的文档。文档尊重标准,并清楚地标记所有非标准扩展,以便您知道哪个是。

SGI也有在线文档(尽管它较旧,在某些情况下,并不完全准确)。

IBM在其网站上提供了类似的文档,我相信GCC也是如此。

答案 6 :(得分:1)

我当然希望没有办法访问优先级队列的底层容器。如果可以,那么你可能会搞乱优先级队列的内部堆结构。在任何情况下,这些适配器的要点是它们为您提供堆栈或队列的最小接口,并抽象出所有其他东西。因此,如果您需要使用任何其他功能,您应该直接使用原始容器。

关于STL的文档,您可以查看SGI的STL here的文档。 SGI的STL和C ++标准中的STL之间存在一些差异,但它们主要在该站点上注明。此外,cppreference.com是C ++库的维基文档,它正在变得更加完整。

答案 7 :(得分:0)

您可以编写子类来检索成员变量c。 请参阅libstdc ++中的这条评论。

{{1}}

答案 8 :(得分:0)

这应该适用于最近的 ISO 编译器:

<div class='flex-parent'>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
  <div class='flex-child'>CHILD</div>
</div>

用法:

template <typename T, typename Seq = std::vector<T>,
            typename Cmp = std::less<typename Seq::value_type>>
  class PriorityQueueContainer : public std::priority_queue<T, Seq, Cmp> {
   public:
    using base_t = std::priority_queue<T, Seq, Cmp>;
    PriorityQueueContainer() = default;
    template <typename Cont>
    PriorityQueueContainer(Cont&& cont) : base_t(Cmp{}, std::move(cont)) {}
    template <typename Cmp, typename Cont>
    PriorityQueueContainer(const Cmp& cmp, Cont&& cont) : base_t(cmp, std::move(cont)) {}
    template <typename Cont>
    PriorityQueueContainer(const Cont& cont) : base_t(Cmp{}, cont) {}

    static Seq&& retrieve_container(PriorityQueueContainer&& pq) {
      return std::move(pq.c);
    }
  };

答案 9 :(得分:-2)

在哪里可以找到标准库的官方文档?

C ++标准有精装版,ISBN 0470846747。 标准草案以PDF格式广泛提供,但您必须小心将它们与官方版本(C ++ 98,03,11或14)相匹配。目前的草案超过了C ++ 14标准。