Reputation: 1591
I want to implement a container of generic types of element; and I want this container to support comparer.
When using STL's priority queue, I could define a comparer and initialise my priority queue container instance like this:
bool IsMyItemLarger(MyItem* a, MyItem* b) {
if(a && b && a->value > b->value)
return true;
return false;
}
std::priority_queue<
MyItem*,
vector<MyItem*>,
std::function<bool(MyItem*, MyItem*)>
> pq(IsMyItemLarger);
Now, I'd like to define my own container class, I'd like it to support any type including primitive type, so a template T should be in the class definition.
template<typename T...>
class MyContainer {
public:
vector<T*> items;
};
However, how can I define the comparer stub in my container class? (so that the client can pass e.g. "bool(MyItem*, MyItem*)" as a template argument and "IsMyItemLarger" as an argument of constructor?)
Note: (something off topic below!!)
I know how to implement SIMILAR class via interface, e.g.
I defined an interface and only items conforms to this interface can be insert into the container. It could pass compile (following code)
class AbstractBaseItem {
public:
virtual int compareTo(AbstractBaseItem* a) = 0;
};
class MyContainer {
public:
vector<AbstractBaseItem*> items;
bool greater(int i, int j) {
return items[i]->compareTo(items[j]) > 0;
}
};
class MyItem : public AbstractBaseItem {
public:
int value;
int compareTo(AbstractBaseItem* a) {
int aValue = ((MyItem*)a)->value;
if(value > aValue)
return 1;
else if(value < aValue)
return -1;
else
return 0;
}
};
However, logically, I don't want to use virtual functionality. All items in the container should be exactly the same type, not "as-is" type. E.g. I just want MyItem be in the container, not MyItem, YourItem, HisItem etc although these class all inherits from AbstractBaseItem. And it could be a primitive type like int, long, double...
So a template is actually what I wanted.
Upvotes: 1
Views: 90
Reputation: 8492
The comparison is delegated to another templated type, for convenience often left defaulted to std::greater<T>
which does exactly what it seems to do; it's already available in the standard library, along with many other operations like less
, greater_equal
and so on, so no need to rewrite them. They're called operator wrappers and are available in
<functional>
.
Therefore, have
template<typename T, typename Compare>
// ^^^^^^^^^^^^^^^^
class MyContainer {
vector<T*> items;
/* public: */Compare compare;
// ...
{
if ( compare(T1, T2) )
}
};
The signature for Compare
must be
template <class T> bool cmp(const T&, const T&);
or similar in order to keep a standard design, where cmp(a, b)
is expected to be a valid expression; of course, yours may different. More info about it here.
Containers generally allow you to use the comparator object they received, so you may want to make it public
as well.
Tips, if I may:
vector<T>
: pointers are bad; if you have to use them, prefer smart pointers.std::function
, just a callable object (plain functions, lambda ecc.)Upvotes: 2