使用 std::copy 插入 STL 队列

发布于 2024-08-10 13:22:46 字数 534 浏览 10 评论 0原文

我想使用 std::copy 将元素插入到队列中,如下所示:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );

queue<int> q;

copy( v.begin(), v.end(), insert_iterator< queue<int> >( q, q.front() ) );

但这无法编译,抱怨 begin 不是 的成员std::queue

注意:我也用 std::inserter 尝试过 - 这也失败了,这次说“reference”不是“std::queue”的成员。 std::back_inserterstd::back_insert_iterator 也因相同的错误而失败。

我是否遗漏了一些明显的东西,或者 insert_iterator 是否不适用于队列?

I'd like to use std::copy to insert elements into a queue like this:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );

queue<int> q;

copy( v.begin(), v.end(), insert_iterator< queue<int> >( q, q.front() ) );

But this fails to compile, complaining that begin is not a member of std::queue.

Note: I tried it with std::inserter too - this also failed, this time saying that 'reference' is not a member of 'std::queue'. std::back_inserter and std::back_insert_iterator also fail with the same error.

Am I missing something obvious, or do insert_iterators just not work with queues?

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

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

发布评论

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

评论(9

泪意 2024-08-17 13:22:46

不幸的是,std::queue 将名为 push_back 的函数“调整”为 push,这意味着标准 back_insert_iterator不起作用。

可能最简单的方法(尽管概念上很难看)是使用一个短暂的容器适配器适配器[原文如此](呃!)来调整容器适配器,该适配器的寿命与后插入迭代器的寿命一样长。

template<class T>
class QueueAdapter
{
public:
    QueueAdapter(std::queue<T>& q) : _q(q) {}
    void push_back(const T& t) { _q.push(t); }

private:
    std::queue<T>& _q;
};

像这样使用:

std::queue<int> qi;

QueueAdapter< std::queue<int> > qiqa( qi );

std::copy( v.begin(), v.end(), std::back_inserter( qiqa ) );

Unfortunately std::queue 'adapts' the function known as push_back to just push which means that the standard back_insert_iterator doesn't work.

Probably the simplest way (albeit conceptually ugly) is to adapt the container adapter with a short lived container adapter adapter[sic] (eugh!) that lives as long as the back insert iterator.

template<class T>
class QueueAdapter
{
public:
    QueueAdapter(std::queue<T>& q) : _q(q) {}
    void push_back(const T& t) { _q.push(t); }

private:
    std::queue<T>& _q;
};

Used like this:

std::queue<int> qi;

QueueAdapter< std::queue<int> > qiqa( qi );

std::copy( v.begin(), v.end(), std::back_inserter( qiqa ) );
稚气少女 2024-08-17 13:22:46

队列不允许迭代其元素。

来自 SGI STL 文档

队列是一个适配器,它提供
容器的受限子集
功能 队列是“第一个
先出”(FIFO)数据结构。 1
也就是说,将元素添加到
排在队列后面,可能会被删除
从前面; Q.front() 是
添加到队列中的元素
至少最近。队列不允许
迭代其元素。 [2]

可以完成这项工作,但您不能使用insert_iterator。您必须编写类似 queue_inserter 的内容来呈现迭代器接口。

更新 我无法控制自己,决定尝试实现您需要的迭代器。结果如下:

template< typename T, typename U >
class queue_inserter {
    queue<T, U> &qu;  
public:
    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U> operator ++ (int) { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};

template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q) {
    return queue_inserter<T,U>(q);
}    

这对于这样的函数非常有用:

template<typename II, typename OI>
void mycopy(II b, II e, OI oi) {
    while (b != e) { *oi++ = *b++; }
}

但它不适用于 STL 副本,因为 STL 很愚蠢。

Queue does not allow iteration through its elements.

From the SGI STL Docs:

A queue is an adaptor that provides a
restricted subset of Container
functionality A queue is a "first in
first out" (FIFO) data structure. 1
That is, elements are added to the
back of the queue and may be removed
from the front; Q.front() is the
element that was added to the queue
least recently. Queue does not allow
iteration through its elements. [2]

You can make this work, but you can't use insert_iterator. You'll have to write something like queue_inserter that presents an iterator interface.

Update I couldn't help myself and deicded to try to implement the iterator you need. Here are the results:

template< typename T, typename U >
class queue_inserter {
    queue<T, U> &qu;  
public:
    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U> operator ++ (int) { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};

template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q) {
    return queue_inserter<T,U>(q);
}    

This works great for functions like this:

template<typename II, typename OI>
void mycopy(II b, II e, OI oi) {
    while (b != e) { *oi++ = *b++; }
}

But it doesn't work with the STL copy because the STL is stupid.

淡紫姑娘! 2024-08-17 13:22:46

std::queue 不是 STL 意义上的容器,它是一个功能非常有限的容器适配器。对于您似乎需要的 std::vectorstd::deque (“双端队列,这是一个“真正的容器”),似乎是正确的选择。

std::queue isn't a container in the STL sense, it's a container adapter with very limited functionality. For what you seem to need either std::vector or std::deque ("double-ended queue, which is a "real container"), seems the right choice.

狂之美人 2024-08-17 13:22:46

我很确定它不会工作 - 队列提供 push,但插入迭代器期望使用 push_frontpush_back。没有真正的理由你不能编写自己的 push_insert_iterator (或任何你喜欢的名称),但这有点痛苦......

I'm pretty sure it just won't work -- a queue provides push, but an insert iterator expects to use push_front or push_back. There's no real reason you couldn't write your own push_insert_iterator (or whatever name you prefer) but it is a bit of a pain...

各自安好 2024-08-17 13:22:46

insert_iteratorback_insert_iterator 仅适用于具有(分别)insertpush_back 方法的容器(或适配器) - queue 没有这些。您可以以这些为模型编写自己的迭代器,如下所示:

template <typename Container> 
class push_iterator : public iterator<output_iterator_tag,void,void,void,void>
{
public:
    explicit push_iterator(Container &c) : container(c) {}

    push_iterator &operator*() {return *this;}
    push_iterator &operator++() {return *this;}
    push_iterator &operator++(int) {return *this;}

    push_iterator &operator=(typename Container::const_reference value)
    {
         container.push(value);
         return *this;
    }
private:
    Container &container;
};

除非这样的东西已经存在,但我很确定它不存在。

insert_iterator and back_insert_iterator only work on containers (or adaptors) with (respectively) insert and push_back methods - queue doesn't have these. You could write your own iterator modelled on these, something like this:

template <typename Container> 
class push_iterator : public iterator<output_iterator_tag,void,void,void,void>
{
public:
    explicit push_iterator(Container &c) : container(c) {}

    push_iterator &operator*() {return *this;}
    push_iterator &operator++() {return *this;}
    push_iterator &operator++(int) {return *this;}

    push_iterator &operator=(typename Container::const_reference value)
    {
         container.push(value);
         return *this;
    }
private:
    Container &container;
};

Unless such a thing already exists, but I'm pretty sure it doesn't.

空心↖ 2024-08-17 13:22:46

std::queue 不是 STL 中的基本容器之一。它是一个容器适配器,使用基本 STL 容器之一构建(在本例中是顺序容器之一 std::vector std::dequestd::list)。它是专为 FIFO 行为而设计的,并且不会在您希望 insert_iterator 工作的给定迭代器处提供随机插入。因此不可能像这样使用队列。

我能想到的最简单的方法是:

class PushFunctor
{
public:
    PushFunctor(std::queue<int>& q) : myQ(q)
    {
    }
    void operator()(int n)
    {
        myQ.push(n);
    }

private:
    std::queue<int>& myQ;
};

并像这样使用它:

queue<int> q;
PushFunctor p(q);
std::for_each(v.begin(), v.end(), p);

std::queue is not one of the basic containers in STL. It is a container adaptor which is built using one of the basic STL containers ( in this case one of the sequential container either std::vector std::deque or std::list). It is designed specifically for FIFO behaviour and does not provide random insertion at the given iterator which you want for the insert_iterator to work. Hence it will not be possible to use queue like this.

The easiest way I could think of to do this is to:

class PushFunctor
{
public:
    PushFunctor(std::queue<int>& q) : myQ(q)
    {
    }
    void operator()(int n)
    {
        myQ.push(n);
    }

private:
    std::queue<int>& myQ;
};

And use it like:

queue<int> q;
PushFunctor p(q);
std::for_each(v.begin(), v.end(), p);
山田美奈子 2024-08-17 13:22:46

您需要的是一个push_inserter(即执行push到队列中的插入器)。据我所知,STL中没有这样的迭代器。我通常所做的就是遗憾地回到旧的 for 循环。

如果你有勇气,你可以推出你自己的迭代器,大致如下:

template <typename Container>
class push_insert_iterator
{
  public:
    typedef Container                      container_type;
    typedef typename Container::value_type value_type;

    explicit push_insert_iterator(container_type & c)
        : container(c)
    {}    // construct with container

    push_insert_iterator<container_type> & operator=(const value_type & v)
    {
        //push value into the queue
        container.push(v);
        return (*this);
    }

    push_insert_iterator<container_type> & operator*()
    {
        return (*this);
    }

    push_insert_iterator<container_type> & operator++()
    {
        // Do nothing
        return (*this);
    }

    push_insert_iterator<container_type> operator++(int)
    {
        // Do nothing
        return (*this);
    }

  protected:
    container_type & container;    // reference to container
};

template <typename Container>
inline push_insert_iterator<Container> push_inserter(Container & c)
{
    return push_insert_iterator<Container>(c);
}

这只是一个草稿,但你已经明白了。使用push 方法(例如queuestack)与任何容器(或​​者容器适配器)一起使用。

What you need is a push_inserter (i.e. an inserter that performs pushes into the queue). As far as I know, there is no such iterator in the STL. What I usually do is sadly fall back to the good old for loop.

If you have the courage, you can roll your own iterator, something along these lines:

template <typename Container>
class push_insert_iterator
{
  public:
    typedef Container                      container_type;
    typedef typename Container::value_type value_type;

    explicit push_insert_iterator(container_type & c)
        : container(c)
    {}    // construct with container

    push_insert_iterator<container_type> & operator=(const value_type & v)
    {
        //push value into the queue
        container.push(v);
        return (*this);
    }

    push_insert_iterator<container_type> & operator*()
    {
        return (*this);
    }

    push_insert_iterator<container_type> & operator++()
    {
        // Do nothing
        return (*this);
    }

    push_insert_iterator<container_type> operator++(int)
    {
        // Do nothing
        return (*this);
    }

  protected:
    container_type & container;    // reference to container
};

template <typename Container>
inline push_insert_iterator<Container> push_inserter(Container & c)
{
    return push_insert_iterator<Container>(c);
}

This is just a draft but you got the idea. Works with any container (or, well, container adapters) with a push method (e.g. queue, stack).

迷鸟归林 2024-08-17 13:22:46

对于 c++11

std::for_each( v.begin(), v.end(), [&q1](int data) {  q1.push(data); }  );

和 c++14

std::for_each( v.begin(), v.end(), [&q1](auto data) {  q1.push(data); }  );

for c++11

std::for_each( v.begin(), v.end(), [&q1](int data) {  q1.push(data); }  );

and c++14

std::for_each( v.begin(), v.end(), [&q1](auto data) {  q1.push(data); }  );
只为守护你 2024-08-17 13:22:46

在这个简单的例子中,您可以这样写:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );

queue<int, vector<int> > q(v);

这将复制向量并将其用作队列的底层容器。

当然,如果您需要在构建队列后将事物放入队列,则这种方法将不起作用。

In this simple case, you can write:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );

queue<int, vector<int> > q(v);

This will make a copy of the vector and use it as the underlying container of the queue.

Of course, this approach won't work if you need to enqueue things after the queue has been constructed.

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