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

发布于 2024-07-29 16:46:29 字数 1305 浏览 4 评论 0 原文

是否有一种标准方式来访问stackqueuepriority_queue ?

我在stackqueueVS2008实现中发现了一种名为:_Get_container()的方法,但没有人<代码>优先级队列! 我认为无论如何这都不标准。

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


只是为了澄清,我并不想搞乱底层容器。 我想做的就是这样:

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() 不是标准的,并且 VS2008 中没有 priority_queue 。代码> 实现。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

溇涏 2024-08-05 16:46:29

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

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

玩得开心:)。

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 :).

对你而言 2024-08-05 16:46:29

基于接受的答案,一种更通用的方法:

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

正如我从这个答案.*&实际上是两个运算符,其中&hack::c产生的指针(其类型为 ADAPTER::container_type ADAPTER::*)是用于检索底层容器本身的目标或 .* 运算符。 hack 可以访问受保护的成员,但获得指针后,保护就会丢失。 所以 a.*(&hack::c) 是允许的。

Based on the accepted answer, a more general approach:

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

As I learned from this answer, .*& is actually two operators, where the pointer resulting from &hack::c (which has type ADAPTER::container_type ADAPTER::*) is the target or the .* operator to retrieve the underlying container itself. hack has access to the protected member, but after the pointer is obtained, protections are lost. So a.*(&hack::c) is allowed.

一枫情书 2024-08-05 16:46:29

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

我知道典型的智慧是由于非虚拟 dtor 而不要从 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 。 * 到 Adapter; > *。 从技术上讲,这可能会很好地工作......但我建议不要这样做:

    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 来轻松在两者之间进行交换。 (另请注意,在我的示例中,由于 typedef 的自由使用,您只需更改 1 行即可将其从 queue 更改为 stack >s)。

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> > *. 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 the liberal use of typedefs).

小嗷兮 2024-08-05 16:46:29

不,没有标准的方法可以做到这一点。 至于访问该标准,它在网络上不可用,您必须购买副本! 但有各种草稿副本
可在此处获取

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.

简美 2024-08-05 16:46:29

我相信,这个 SGI 页面是最“官方”的在线文档。

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

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

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(); }
};
请持续率性 2024-08-05 16:46:29

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

至于在哪里可以找到文档,它分为几个部分。

权威来源当然是语言标准。 正如尼尔·巴特沃斯所说,网上有免费的草稿副本(仍然非常有用。与最终版本的差异非常小)。 或者,您可以购买副本。 它应该可以从您所在国家代表 ISO 的任何组织获得(也可能从无数其他来源获得)。 您要查找的文档是 ISO/IEC 14882:2003 编程语言 C++。 (14882是标准编号。2003年是最后一次修订的年份。如果你遇到过1998年的版本,也可以使用它。两者之间的差异确实小得离谱,基本上只是一些澄清。可能最好远离 C++0x 的草案,因为那里的更改要广泛得多)

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

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

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

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

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.

玉环 2024-08-05 16:46:29

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

至于STL的文档,你可以在这里查看SGI的STL文档。 SGI 的 STL 与 C++ 标准中的 STL 之间存在一些差异,但它们大多在该网站上注明。 此外,cppreference.com 是 C++ 库的 wiki 文档,该文档正在变得更加完整。

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.

看春风乍起 2024-08-05 16:46:29

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

protected:
/**
 *  'c' is the underlying container.  Maintainers wondering why
 *  this isn't uglified as per style guidelines should note that
 *  this name is specified in the standard, [23.2.3.1].  (Why?
 *  Presumably for the same reason that it's protected instead
 *  of private: to allow derivation.  But none of the other
 *  containers allow for derivation.  Odd.)
 */
_Sequence c;

You can write a subclass to retrieve the member variable c.
See this comment from libstdc++.

protected:
/**
 *  'c' is the underlying container.  Maintainers wondering why
 *  this isn't uglified as per style guidelines should note that
 *  this name is specified in the standard, [23.2.3.1].  (Why?
 *  Presumably for the same reason that it's protected instead
 *  of private: to allow derivation.  But none of the other
 *  containers allow for derivation.  Odd.)
 */
_Sequence c;
猫弦 2024-08-05 16:46:29

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

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

用法:

 PriorityQueueContainer<int> pq();
 std::vector<int> retrieve = PriorityQueueContainer<int>::retrieve_container(std::move(pq));

This should work on recent ISO compilers:

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

Usage:

 PriorityQueueContainer<int> pq();
 std::vector<int> retrieve = PriorityQueueContainer<int>::retrieve_container(std::move(pq));
開玄 2024-08-05 16:46:29

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

C++ 标准有精装本,ISBN 0470846747。
标准草案以 PDF 形式广泛存在,但您必须小心地将它们与官方版本(C++98、03、11 或 14)相匹配。 当前的草案超出了 C++14 标准。

where can I find official documentation of the standard library?

The C++ standard is available in hardcover, ISBN 0470846747.
Drafts of Standard are widely available in PDF form, but you'll have to be careful to match them with the official versions (C++98,03,11 or 14). The current drafts exceed the C++14 standard.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文