C++ 什么';为同一类提供不同比较运算符的最佳策略是什么?

C++ 什么';为同一类提供不同比较运算符的最佳策略是什么?,c++,c++11,operators,C++,C++11,Operators,考虑这个存储值和时间的简单类 class A { public: boost::posix_time::ptime when; double value; }; 根据上下文,我需要按值或时间比较A的两个实例(和/或将它们存储在集中/map,有时按值排序,有时按时间排序) 提供操作员IMHO最通用的方法是两步流程: 制作ADL吸气剂 根据这些getter编写比较概念 例如: #include <boost/date_time.hpp> #include <set

考虑这个存储值和时间的简单类

class A
{
public:
    boost::posix_time::ptime when;
    double value;
};
根据上下文,我需要按值或时间比较
A
的两个实例(和/或将它们存储在
集中
/
map
,有时按值排序,有时按时间排序)


提供
操作员IMHO最通用的方法是两步流程:

  • 制作ADL吸气剂

  • 根据这些getter编写比较概念

  • 例如:

    #include <boost/date_time.hpp>
    #include <set>
    #include <vector>
    #include <algorithm>
    
    class A
    {
    public:
        boost::posix_time::ptime when;
        double value;
    };
    
    // get the 'when' from an A
    auto get_when(A const& a) -> boost::posix_time::ptime 
    { 
        return a.when; 
    }
    
    // get the 'when' from a ptime (you could put this in the boost::posix_time namespace for easy ADL    
    auto get_when(boost::posix_time::ptime t) -> boost::posix_time::ptime 
    { 
        return t; 
    }
    
    // same for the concept of a 'value'
    auto get_value(A const& a) -> double 
    { 
        return a.value; 
    }
    
    auto get_value(double t) -> double 
    { 
        return t; 
    }
    
    // compare any two objects by calling get_when() on them    
    struct increasing_when
    {
        template<class L, class R>
        bool operator()(L&& l, R&& r) const
        {
            return get_when(l) < get_when(r);
        }
    };
    
    // compare any two objects by calling get_value() on them    
    struct increasing_value
    {
        template<class L, class R>
        bool operator()(L&& l, R&& r) const
        {
            return get_value(l) < get_value(r);
        }
    };
    
    
    void example1(std::vector<A>& as)
    {
        // sort by increasing when
        std::sort(begin(as), end(as), increasing_when());
    
        // sort by increasing value
        std::sort(begin(as), end(as), increasing_value());
    }
    
    int main()
    {
        // same for associative collections
        std::set<A, increasing_when> a1;
        std::set<A, increasing_value> a2;
    }
    
    #包括
    #包括
    #包括
    #包括
    甲级
    {
    公众:
    boost::posix_time::ptime when;
    双重价值;
    };
    //从A中获取“时间”
    自动获取时间(常量和A)->boost::posix_时间::ptime
    { 
    返回a.when;
    }
    //从ptime获取“when”(您可以将其放在boost::posix_时间名称空间中,以方便ADL
    自动获取时间(boost::posix_time::ptime t)->boost::posix_time::ptime
    { 
    返回t;
    }
    //“价值”的概念也是如此
    自动获取_值(常数A)->double
    { 
    返回a.value;
    }
    自动获取_值(双t)->双
    { 
    返回t;
    }
    //通过对任意两个对象调用get_when()来比较它们
    当
    {
    模板
    布尔运算符()(L&&L,R&&R)常量
    {
    返回get_when(l)
    更新:

    如果需要,可以将比较模板化:

    template<class Comp>
    struct compare_when
    {
        template<class L, class R>
        bool operator()(L&& l, R&& r) const
        {
    
            return comp(get_when(l), get_when(r));
        }
    
        Comp comp;
    };    
    
    using increasing_when = compare_when<std::less<>>;
    using decreasing_when = compare_when<std::greater<>>;
    
    模板
    结构比较
    {
    模板
    布尔运算符()(L&&L,R&&R)常量
    {
    返回comp(get_when(l),get_when(r));
    }
    Comp-Comp;
    };    
    使用递增时=比较时;
    使用递减时=比较时;
    
    要在代码中直接使用比较,请执行以下操作:

    auto comp = compare_when<std::greater<>>();
    if (comp(x,y)) { ... }
    
    auto comp=compare_when();
    如果(comp(x,y)){…}
    
    简短回答:不要 我在一篇评论中解释了原因,主要原因是,它在代码中引入了歧义,降低了可读性,这与运算符的作用相反。只需使用不同的方法,并提供选择用于此排序的方法的方法(如比较器).当我输入这些时,人们发布了一些很好的例子,甚至有些人使用了一些元编程

    然而,从科学角度来说,你可以这样做。虽然你不能向操作符添加参数(二进制操作符是二进制操作符,而且似乎没有语法可以在某个地方添加第三个参数),但你可以让操作符在不同的上下文中有不同的含义(c++上下文,对于一行代码或由{}分隔的块)

    这里使用构造/销毁顺序快速完成(类似于普通锁的实现,不考虑线程安全):

    比较如下:

    Thing::thingSortingMode(Thing::thingSortingMode::alternateMode), Thing{1, 2} < Thing{3, 4};
    

    针对UKMonkey的评论,定义我所理解的可命名为“comparator类”的内容是否是一种好的方法/实践

    class A
    {
    public:
        boost::posix_time::ptime when;
        double value;
    
        const boost::posix_time::ptime& getTime() const { return when; }
        double getValue() const { return value; }
    };
    
    template <typename T>
    class CompareBy
    {
    public:
        CompareBy( const A& a, T (A::*getter)() const ) : a(a), getter(getter)
        {}
    
        bool operator<( const CompareBy& right ) const
        {
            return (a.*getter)() < (right.a.*getter)();
        }
    
        // you may also declare >, <=, >=, ==, != operators here
    
    private:
        const A& a;
        T (A::*getter)() const;
    };
    
    class CompareByTime : public CompareBy<const boost::posix_time::ptime&>
    {
    public:
        CompareByTime(const A& a) : CompareBy(a, &A::getTime)
        {
        }
    };
    
    class CompareByValue : public CompareBy<double>
    {
    public:
        CompareByValue( const A& a ) : CompareBy(a, &A::getValue)
        {
        }
    };
    
    struct byTime_compare {
        bool operator() (const A& lhs, const A& rhs) const {
            return CompareByTime(lhs) < CompareByTime(rhs);
        }
    };
    
    int main()
    {
        A a, b;
    
        ...
    
        if (CompareByValue(a) < CompareByValue(b))
        {
            ...
        }
    
        std::set<A, byTime_compare> mySet;
    }
    
    A类
    {
    公众:
    boost::posix_time::ptime when;
    双重价值;
    常量boost::posix_time::ptime&getTime()常量{return when;}
    双getValue()常量{返回值;}
    };
    模板
    类比较
    {
    公众:
    比较(常数A&A,T(A::*getter)(常数):A(A),getter(getter)
    {}
    布尔运算符,=,=,!=此处的运算符
    私人:
    康斯特A&A;
    T(A::*getter)()常数;
    };
    类比较时间:公共比较时间
    {
    公众:
    CompareByTime(常量A&A):CompareBy(A,&A::getTime)
    {
    }
    };
    类CompareByValue:公共CompareBy
    {
    公众:
    CompareByValue(常量A&A):CompareBy(A,&A::getValue)
    {
    }
    };
    按时间比较结构{
    布尔运算符()(常数A和lhs、常数A和rhs)常数{
    返回CompareByTime(lhs)
    另一种方法,非常简单:将模板比较器函数添加到A类中,这样最终比较起来很容易,而且很容易出错:

    #include <iostream>
    #include <set>
    
    using namespace std;
    
    class A
    {
    public:
        int when;
        double value;
    
        int getTime() const { return when; }
        double getValue() const { return value; }
    
        template<typename T>
        bool isLower( T (A::*getter)() const,
                      bool strict,
                      const A& right ) const
        {
            if ( strict )
                return ((*this).*getter)() < (right.*getter)();
            else
                return ((*this).*getter)() <= (right.*getter)();
        }
    
        template<typename T>
        bool isGreater( T (A::*getter)() const,
                        bool strict,
                        const A& right ) const
        {
            if ( strict )
                return ((*this).*getter)() > (right.*getter)();
            else
                return ((*this).*getter)() >= (right.*getter)();
        }
    
        template<typename T>
        bool isEqual( T (A::*getter)() const,
                      const A& right ) const
        {
            return ((*this).*getter)() == (right.*getter)();                  
        }
    };
    
    struct byTime_compare {
        bool operator() (const A& lhs, const A& rhs) const {
            return lhs.isLower( &A::getTime, true, rhs );
        }
    };
    
    int main()
    {
        A a, b;
    
        if ( a.isLower( &A::getValue, true, b ) ) // means a < b by value
        {
            // ...
        }
    
        std::set<A, byTime_compare> mySet;
    }
    
    #包括
    #包括
    使用名称空间std;
    甲级
    {
    公众:
    int时;
    双重价值;
    int getTime()常量{return when;}
    双getValue()常量{返回值;}
    模板
    布尔岛(T(A::*getter)()常数,
    布尔严格,
    常数A(右)常数
    {
    如果(严格)
    返回((*this)。*getter)(<(右。*getter)();
    其他的
    返回((*this)。*getter)((右。*getter)();
    其他的
    返回((*this)。*getter)(>=(右。*getter)();
    }
    模板
    bool-isEqual(T(A::*getter)()const,
    常数A(右)常数
    {
    返回((*this)。*getter)(==(右。*getter)();
    }
    };
    按时间比较结构{
    布尔运算符()(常数A和lhs、常数A和rhs)常数{
    返回lhs.isLower(&A::getTime、true、rhs);
    }
    };
    int main()
    {
    A,b;
    if(a.isLower(&a::getValue,true,b))//表示a
    为什么不能为sort提供comparitor类?^这意味着,当有不同的合法方式对事物进行排序时,如果有人阅读“”或“==”,则不同的人可能会对其进行不同的解释(理解:大多数情况下都是错误的),因此会使代码变得更糟糕,更难维护。我可以找到一些方法来实现这一点(比如在上下文中设置运算符的含义)但是在c++@UKMonkey中,比较器是提供不同比较以进行排序的标准方法:什么是“比较器?”
    mode: 1 -> 3
    
    mode: 3 -> 2
    
    mode: 2 -> 4
    
    mode: 4 -> 1
    end sub 3 (mode 1)
    
    mode: 1 -> 4
    
    mode: 4 -> 1
    
    mode: 1 -> 2
    this is the kind of things that might behave strangely
    here both are printed in mode 2, but it's a direct consequence of the order in which this expression is evaluated
    
    mode: 2 -> 1
    
    mode: 1 -> 4
    end sub 2 (mode 4). Not that we still pop our states in the right order, even if we screwed up the previous line
    
    mode: 4 -> 2
    
    mode: 2 -> 2
    this on the other hand (mode 2)
    
    mode: 2 -> 1
    works (mode 1)
    
    mode: 1 -> 2
    
    mode: 2 -> 2
    end sub 1 (mode 2)
    
    mode: 2 -> 3
    end main (mode 3)
    
    mode: 3 -> 1
    
    class A
    {
    public:
        boost::posix_time::ptime when;
        double value;
    
        const boost::posix_time::ptime& getTime() const { return when; }
        double getValue() const { return value; }
    };
    
    template <typename T>
    class CompareBy
    {
    public:
        CompareBy( const A& a, T (A::*getter)() const ) : a(a), getter(getter)
        {}
    
        bool operator<( const CompareBy& right ) const
        {
            return (a.*getter)() < (right.a.*getter)();
        }
    
        // you may also declare >, <=, >=, ==, != operators here
    
    private:
        const A& a;
        T (A::*getter)() const;
    };
    
    class CompareByTime : public CompareBy<const boost::posix_time::ptime&>
    {
    public:
        CompareByTime(const A& a) : CompareBy(a, &A::getTime)
        {
        }
    };
    
    class CompareByValue : public CompareBy<double>
    {
    public:
        CompareByValue( const A& a ) : CompareBy(a, &A::getValue)
        {
        }
    };
    
    struct byTime_compare {
        bool operator() (const A& lhs, const A& rhs) const {
            return CompareByTime(lhs) < CompareByTime(rhs);
        }
    };
    
    int main()
    {
        A a, b;
    
        ...
    
        if (CompareByValue(a) < CompareByValue(b))
        {
            ...
        }
    
        std::set<A, byTime_compare> mySet;
    }
    
    #include <iostream>
    #include <set>
    
    using namespace std;
    
    class A
    {
    public:
        int when;
        double value;
    
        int getTime() const { return when; }
        double getValue() const { return value; }
    
        template<typename T>
        bool isLower( T (A::*getter)() const,
                      bool strict,
                      const A& right ) const
        {
            if ( strict )
                return ((*this).*getter)() < (right.*getter)();
            else
                return ((*this).*getter)() <= (right.*getter)();
        }
    
        template<typename T>
        bool isGreater( T (A::*getter)() const,
                        bool strict,
                        const A& right ) const
        {
            if ( strict )
                return ((*this).*getter)() > (right.*getter)();
            else
                return ((*this).*getter)() >= (right.*getter)();
        }
    
        template<typename T>
        bool isEqual( T (A::*getter)() const,
                      const A& right ) const
        {
            return ((*this).*getter)() == (right.*getter)();                  
        }
    };
    
    struct byTime_compare {
        bool operator() (const A& lhs, const A& rhs) const {
            return lhs.isLower( &A::getTime, true, rhs );
        }
    };
    
    int main()
    {
        A a, b;
    
        if ( a.isLower( &A::getValue, true, b ) ) // means a < b by value
        {
            // ...
        }
    
        std::set<A, byTime_compare> mySet;
    }