Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ templated container class: How to best support both ordered and un-ordered item types?

I'm writing a templated C++ generic container class that can optionally maintain its contents in a well-defined order. Previously it used function pointers to order its contents in a sensible type-specific way, but I am attempting to change it to use templated functor arguments instead.

Since it's often the case that the class's user might want to keep items of the same type sorted in different ways in different containers, the container class takes an optional template argument that lets the user optionally specify his own compare-functor:

template <class ItemType, class CompareFunctorType = CompareFunctor<ItemType> > class MyContainer
{
    [...]
};

If the class user doesn't specify a custom functor type, it uses the following CompareFunctor definition by default:

template <typename ItemType> class CompareFunctor
{
public:
    bool IsItemLessThan(const ItemType & a, const ItemType & b) const
    {
       return (a<b);   // will compile only for types with < operator
    }
};

This works great for built-in types and also user-defined types where a less-than operator has been defined. However, I'd like it to also automatically work for types where there is no built-in or explicitly defined less-than operator. For those types, the ordering of the items within the container is not important.

The motivation is that I use this container to hold a lot of different types, and most of the time, I don't care about the order of the types in the container, but in some cases I do... and I don't want to have to go in and add "dummy" less-than operators to all of these different types just so I can use them with this container class... and I don't want to have to explicitly specify a custom "dummy" CompareFunctor argument every time I use the table to store items that don't have a less-than operator.

So, is there a way I can use template specialization (or something) so that the default CompareFunctor (shown above) is used whenever possible, but in cases where that CompareFunctor would cause an error, C++ would automatically fall back to a "dummy" FallbackCompareFunctor like the one below? Or perhaps some other clever way to handle this dilemna?

template <typename ItemType> class FallbackCompareFunctor
{
public:
    bool IsItemLessThan(const ItemType & a, const ItemType & b) const
    {
       return ((&a)<(&b));   // will compile for all types (useful for types where the ordering is not important)
    }
};
like image 231
Jeremy Friesner Avatar asked Nov 21 '25 01:11

Jeremy Friesner


2 Answers

For your default unsorted case, use a Null Comparison functor that just returns false for all cases.
You can then specialise your template to a sorted container using the std::less() functor.

       template<class T>
       struct NullCompare: public binary_function <T, T, bool> 
       {
          bool operator()(const T &l, const T &r) const
          {
              // edit: previously had "return true;" which is wrong.
              return false;
          }
       };

       template <class T, class Compare=NullCompare<T> > 
       class MyContainer
       {
           [...]
       };

       template <class T, class Compare=std::less<T> > 
       class MySortedContainer : public MyContainer<T, Compare>
       {
           [...]
       };
like image 161
Michael J Avatar answered Nov 23 '25 14:11

Michael J


While doing some Google searches based on Eugene's answer, I found this article:

http://www.martinecker.com/wiki/index.php?title=Detecting_the_Existence_of_Operators_at_Compile-Time

Perhaps I can adapt the code presented there...

like image 45
Jeremy Friesner Avatar answered Nov 23 '25 13:11

Jeremy Friesner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!