Hi,
I've got a set of elements that I need to store in a container.
The elements look approximately like this:
class element
{
time m_Time;
... Other variables
};
I need a strict ordering between the elements, so the container I chose was std::set<T>. However, because of other requirements, I had to write a class to wrap this set and provide additional functionality. The actual functioning of the container is basically a cross between a stack and a priority queue, where the item with the highest priority must go to the top of the stack. The reason I didn't go with a priority_queue is that I need to be able to iterate over the elements, and I don't believe priority_queue provides iterators. (I'll refer to my container as a "stack" from now on, even though it isn't in the traditional sense).
Now, the problem comes in in that sometimes I need to sort these elements according to one ordering, and sometimes according to another. For example, lets say that I've got an early stack, where the sort functor will return true if a.m_Time < b.m_Time, and I've also got a late stack where the opposite applies. Now, because, for the rest of my code, I don't really care what the ordering is, I just want to go down the stack, I wrote (basically) the following:
struct EarlyFirst : std::binary_predicate<bool, element*, element*>
{
bool operator()(element* a, element* b)
{
return a->m_Time < b->m_Time;
}
};
struct LateFirst : std::binary_predicate<bool, element*, element*>
{
bool operator()(element* a, element* b)
{
return a->m_Time > b->m_Time;
}
};
// Non-template class
class StackPair
{
/* Return Type? */ operator [](char c)
{
if(c == 'E')
{
return early;
}
else
{
return late;
}
}
private:
MyStack<EarlyFirst> early;
MyStack<LateFirst> late;
};
So, typically what happens is that my client code has a char, which is either a 'E' or a 'L', and it asks its StackPair to give it the correct stack based on that character (so that I can treat the stacks independently of their sort order - I always want to go from high-priority to low priority until I satisfy my search conditions).
As you'll see in the code above, StackPair is a non-template class. I can't think why I'd want to make it templated, because it always has 1 EarlyFirst stack, and 1 LateFirst stack. However, this poses a problem with the return type of the [] operator. What should it be so that I can handle the stacks generically?
1) It must be returned by reference - I don't want copies of the stack floating around.
2) There's a fairly narrow interface of requirements which MyStack needs to implement.
For this reason, I decided to make an abstract base class (non-templated) that MyStack would derive from:
class BaseStack
{
public:
void push(element* a)=0;
element* top()=0;
void pop()=0;
... etc
};
template <class T>
class MyStack : public BaseStack
{
private:
void push(element* a);
element* top();
void pop();
std::set<element*, T> m_Elements;
}
// and StackPair becomes:
class StackPair
{
BaseStack& operator [](char c)
{
...
}
};
So far so good. Now, comes the hard part. I want to iterate through the stack elements from begin to end, regardless of whether begin is the earliest, or the latest element. I want the code to look approximately as follows:
void Algorithm(char earlyOrLate)
{
for(BaseStack::iterator it = stackPair[earlyOrLate].begin(); it != stackPair[earlyOrLate].end(); ++it)
{
element* theElement = *it;
// Do something with theElement, etc...
}
}
My question is, is this possible, and if so, how? I want BaseStack::iterator to just wrap std::set<T>::iterator so its use is basically transparent from a client point of view, but the client must not have to know whether it's a std::set<EarlyFirst>::iterator or a std::set<LateFirst>::iterator.
Thanks in advance to anybody who can shed some light on this.
We scratch our eternal itchA twentieth century bitchWe are grateful forOur Iron Lung