1

I need to choose between std::less and std::greater templates and store one in another template (I think I'm using the C++ STL vocab right..?). I have this:

template<typename> class stSortOrder;
stSortOrder = std::less;
if(sortby == "descending")
    {
    stSortOrder = std::greater;
    }

Obviously it doesn't compile. I'm pretty sure it's cause I'm a relative novice at the STL.


CLARIFICATION:

I am implementing the accepted answer in this thread (the variation for public member functions).

Here's what I want to avoid repeating in a switch case:

void CSubscriptionItem::sortMonitoredItems( int nColumnIndex, Qt::SortOrder ulOrder )
    {
    switch(nColumnIndex)
        {
        case CMonitoredItem::NAME:
            {
            if(ulOrder == Qt::DescendingOrder)
                {
                qSort(  m_qlpcMonitoredItems.begin(), 
                        m_qlpcMonitoredItems.end(), 
                        make_method_comparer<std::less>(&CMonitoredItem::getName) );
                }
            else
                {
                qSort(  m_qlpcMonitoredItems.begin(), 
                        m_qlpcMonitoredItems.end(), 
                        make_method_comparer<std::greater>(&CMonitoredItem::getName) );
                }
            break;
            }

I would like to replace std::less and std::greater in make_method_comparer<> with one template that is already set up depending on the sort order argument. This would really help reduce code size.

I've considered both of the answers posted, but they don't seem to work - likely because I am not too familiar with templates and I am simply using them incorrectly.

Community
  • 1
  • 1
kevlar1818
  • 3,055
  • 6
  • 29
  • 43

3 Answers3

2

You will need a auxiliary class to resolve this in run time, do something like:

template <typename T>
class ChosedSorter {
public:
    ChosedSorted(bool descending) : _d(descending)
    {
    }
    bool operator()(const T& a, const T& b) {
        if( _d )
            return _less(a,b);
        return _greater(a,b);
    }
private:
    bool _d;
    std::less<T> _less;
    std::greater<T> _greater;
}

And then you use it like that:

void CSubscriptionItem::sortMonitoredItems( int nColumnIndex, Qt::SortOrder ulOrder )
    {
    switch(nColumnIndex)
        {
        case CMonitoredItem::NAME:
            {
            ChosedSorted<QString> sorter(ulOrder == Qt::DescendingOrder);
                std::sort(  m_qlpcMonitoredItems.begin(), 
                        m_qlpcMonitoredItems.end(), 
                        sorter);
            break;
            }
// ...
André Puel
  • 8,741
  • 9
  • 52
  • 83
  • minor nitpick, _d can be safely read and written to at any point, and should either be public/better name, or have a getter/setter. – Mooing Duck Aug 09 '11 at 18:36
  • 2
    @Mooing: Why? Predicates are throw-away objects. You just create another one instead of altering the state of one. - But why would this functor store `less` and `greater`? It might just as well `return std::less()(a, b);` etc – UncleBens Aug 09 '11 at 21:43
  • I prefer to keep a copy, maybe someone eventually specialize std::less and put something in constructor that is important to the sorting... – André Puel Aug 10 '11 at 03:08
  • As I said in my other comment, I've updated my question. Hopefully it's more clear what I'm looking for. – kevlar1818 Aug 10 '11 at 13:43
  • @UncleBens: but it wouldn't reuse the same predicate. It would construct a new predicate object for every `operator()` call. – jweyrich Aug 10 '11 at 18:28
  • @kevlar1818 create the auxiliary class ChosedSorter and use it inside CSubscriptionItem::sortMonitoredItems. I improved my answer... – André Puel Aug 10 '11 at 18:44
  • The problem is I need to use the method_comparer from [the thread](http://stackoverflow.com/questions/5174115/sorting-a-vector-of-objects-by-a-property-of-the-object) I mentioned in my question. – kevlar1818 Aug 11 '11 at 13:13
2

One can do:

template <typename T>
struct comparer
{
    comparer(bool is_less) : is_less(is_less) {}

    bool operator()(const T& x, const T& y) const
    {
        return is_less ? std::less<T>()(x, y) : std::greater<T>()(x, y);
    } 

private:
    bool is_less;
};

but I'd rather do (clearer):

template <typename T>
struct comparer
{
    bool operator()(const T& a, const T& b) const
    {
        return is_less ? a < b : b < a;
    }

private:
    bool is_less;
};
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • I'm curious why your first example goes to the trouble of defining a union. Wouldn't it be easier to just define both objects as members? – Mark Ransom Aug 09 '11 at 21:44
  • @Mark: the point is to clarify the intent, and less importantly, to save some space (better yet in this respect would have been to be able to inherit from the union). – Alexandre C. Aug 09 '11 at 21:45
  • `less` and `greater` should be dirt-cheap to construct on demand, so why mess with the union. One advantage they might have is that they should have a specialization for pointers, comparing them properly even if they don't point in the same object. – UncleBens Aug 09 '11 at 21:46
  • @UncleBens: I wholeheartedly agree, and really prefer the second solution. However, the OP seems to want to dispatch between `std::less` and `std::greater`. Let me provide a better version. – Alexandre C. Aug 09 '11 at 21:47
  • I've updated my question. Hopefully it's more clear what I'm looking for. – kevlar1818 Aug 10 '11 at 13:43
2

If your compiler supports TR1, you can simply:

std::vector<int> v = { 3, 9, 17, 12, 5, 4 }; // NOTE: C++0x initialiser
const bool ascending = true;
typedef std::tr1::function<bool(int, int)> sort_func;
sort_func& func = ascending
    ? static_cast<sort_func>(std::less<int>())
    : static_cast<sort_func>(std::greater<int>());
std::sort(v.begin(), v.end(), func);

Or, if you have boost, replace std::tr1::function by boost::function.

jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • It's a little more complicated than that. Look at my clarification: I'm using a template to compare objects using public member functions. *That* template requires a class template as well, not a function. – kevlar1818 Aug 10 '11 at 14:02