Std :: set selects a smaller or larger comparator at runtime

I reviewed the code and found that there are two places that can be written with the same code, except that the comparator dials less<double>in one place and greater<double>in another. Sort of:

double MyClass::Function1(double val)
{
    std::set<double, less<double> > s;
    // Do something with s
}

double MyClass::Function2(double val)
{
    std::set<double, greater<double> > s;
    // Do the same thing with s as in Function1
}

So, I was thinking about doing:

double MyClass::GeneralFunction(double val, bool condition)
{  
    if(condition)  
    {  
        // Select greater as comparator  
    }  
    else
    {  
        // Select less as comparator  
    }  

    set<double, comparator> s;  
    // common code
}

I did this using my custom comparator functions, for example:

bool my_greater(double lhs, double rhs)
{
    return lhs > rhs;
}

bool my_less(double lhs, double rhs)
{
    return lhs < rhs;
}

double MyClass::GeneralFunction(double val, bool condition)
{ 
    typedef bool(*Comparator) ( double,  double);
    Comparator comp = &my_less;
    if (condition)
    {
        comp = &my_greater;
    }

    std::set<double, Comparator > s(comp);  

    //....
}

But I would like to use inline ones. The problem is that I don’t know how to declare a comparator and assign built-in predicates to it.

Any help would be greatly appreciated.

+5
source share
4 answers

Do you really need a runtime check?

template <class Comp> double MyClass::Function(double val)
{
    std::set<double, Comp > s;
    // Do something with s
}

Even if you do, you can still use

double MyClass::Function(double val, bool comp)
{
   return comp ? Function<std::less<double> >(val) : Function<std::greater<double> >(val);
}
+4
source

, tuntime std::less std::greater . , std::set, std::less , std::greater. , ( , ) , :

class SelectableCompare
{
    bool myIsGreater;
public:
    SelectableCompare( bool isGreater ) : myIsGreater( isGreater ) {}
    bool operator()( double d1, double d2 ) const
    {
        static std::less<double> const less;
        return myIsGreater
            ? less( d2, d1 )
            : less( d1, d2 );
    }
};

std::less std::greater, . double , , ; d1 > d2 d1 < d2. , , , std::less. std::less; , std::less, , , .

: :

class Comparator
{
public:
    virtual ~Comparator() {}
    virtual bool isLessThan( double d1, double d2 ) const = 0;
};

:

class ComparatorWrapper
{
    std::shared_ptr<Comparator> myComparator;
public:
    ComparatorWrapper( Comparator* newed_comparator )
        : myComparator( newed_comparator )
    {
    }
    bool operator()( double d1, double d2 ) const
    {
        return myComparator->isLessThan( d1, d2 );
    }
};

, , ; a set, ( ).

+4

std::set<double, std::function<bool(double,double)>>

, :

typedef std::set<double, std::function<bool(double,double)> > RTSet;

RTSet choose_ordering(bool increasing)
{
    if (increasing)
        return RTSet( std::less<double>() );
    else
        return RTSet( std::greater<double>() );
}

, :

  • ,
  • , (, )

, , .


, ( ), , , .

An alternative that I used in some situations is to use one sorting direction and a code template acting on the set (as an iterator), so you can do

if (increasing)
    do_stuff(set.begin(), set.end());
else
    do_stuff(set.rbegin(), set.rend());
+3
source

Why not do

template <typename Compare>
double MyClass::GeneralFunction(double val)
{
    std::set<double, Compare> s;

    //....
}

Choosing a template by a formal parameter is not something that C ++ handles very well. Click as much as possible on the compilation phase, indicating that the caller contains a template argument.

Then you can provide a wrapper if you really want to select it at runtime:

double MyClass::GeneralFunction(double val, bool condition)
{
    return condition ?
        GeneralFunction<std::greater<double> >(val) :
        GeneralFunction<std::less   <double> >(val);\
}
+2
source

All Articles