0

How can I apply the std::random_shuffle algorithm with a std::queue? I tried this:

std::random_shuffle(myQueue.front(), myQueue.back());

And gives errors:

  • No match for 'operator-' in '__i- __first'
  • No match for 'operator!=' in '__first != __last'
  • No match for 'operator+' in '__first + 1'
  • No match for 'operator++' in '++ __i'

My queue is holding Card classes, which represent poker cards. I can understand that the error comes from the operations which std::random_shuffle is doing with the queue elements So, even when I don't need a != operator for my Card class, i wrote one and that error is gone.

But what should I do with the rest of the errors? It makes no sense to write operators +, - and ++ for a Card class.

Roman Rdgz
  • 12,836
  • 41
  • 131
  • 207

3 Answers3

6

std::queue is not a container; it's a container adapter. It adapts a sequence container to restrict its interface to simple queue/dequeue operations. In particular, it doesn't let you (easily) iterate over the underlying container, which is what std::random_shuffle needs to do. If you don't want those restrictions, don't use std::queue; use a sequence container (such as vector or deque) directly.

There are ways to subvert its interface and meddle with the underlying container, but it would be much better to choose an appropriate container to start with.

Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Ok, I understand the problem, but I have one doubt here: if deque is a double-queue, why can it have iterators and a queue can't? Makes the same sense to me – Roman Rdgz Dec 11 '12 at 12:23
  • 1
    @RomanRdgz: Because `queue` is an adapter, not a container. It wraps up a container (by default, a `deque`) and presents a simpler, more specific, interface. – Mike Seymour Dec 11 '12 at 12:24
2

std::random_shuffle expects a pair of iterators. Furthermore, an std::queue is not designed to be messed around like that. It maintains the order of its elements by definition. What you can do is create an std::deque, shuffle that, and the construct a queue from it.

std::deque<int> d {5, 1, 67, 89, 32, 444}; // populate in the order you would the queue
std::random_shuffle(d.begin(), d.end());
std::queue<int> q(d);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Would this be neccessary? I mean, once I'm using a std::deque, wouldn't it be better to stay with it using its pop_front and push_front methods? – Roman Rdgz Dec 11 '12 at 12:21
  • @RomanRdgz If you need a queue, better stick with `std::queue`. `std::deque` supports all kinds of operations that a queue shouldn't. – juanchopanza Dec 11 '12 at 12:23
1

std::random_shuffle expects two iterators, but std::queue::front() and std::queue::back() return two references to elements. std::queue does not expose iterators, you it only offers an interface to push back and pop front elements. If you need to iterate over a collection use std::deque (or any of the standard containers).

Claudio
  • 1,658
  • 11
  • 18