为结构定义operator <

Kri*_*son 56 c++ operator-overloading

我有时structs在地图中使用小键作为键,因此我必须operator<为它们定义一个.通常,这最终看起来像这样:

struct MyStruct
{
    A a;
    B b;
    C c;

    bool operator<(const MyStruct& rhs) const
    {
        if (a < rhs.a)
        {
           return true;
        }
        else if (a == rhs.a)
        {
            if (b < rhs.b)
            {
                return true;
            }
            else if (b == rhs.b)
            {
                return c < rhs.c;
            }
        }

        return false;
    }
};
Run Code Online (Sandbox Code Playgroud)

这看起来非常冗长且容易出错.有没有更好的方法,或一些简单的方法来自动定义operator<一个structclass

我知道有些人喜欢使用类似的东西memcmp(this, &rhs, sizeof(MyStruct)) < 0,但是如果成员之间存在填充字节,或者如果char在null终止符之后存在可能包含垃圾的字符串数组,则这可能无法正常工作.

Kon*_*lph 98

这是一个相当古老的问题,因此这里的所有答案都已过时.C++ 11允许更优雅和有效的解决方案:

bool operator <(const MyStruct& x, const MyStruct& y) {
    return std::tie(x.a, x.b, x.c) < std::tie(y.a, y.b, y.c);
}
Run Code Online (Sandbox Code Playgroud)

为什么这比使用更好boost::make_tuple?因为make_tuple将创建所有数据成员的副本,这可能是昂贵的.std::tie相比之下,只会创建一个瘦的引用包装(编译器可能会完全优化).

实际上,上面的代码现在应该被认为是对具有多个数据成员的结构进行词典比较的惯用解决方案.

  • @Riot不,代码工作正常.但是,它确实需要在"MyStruct"之外定义 - 无论如何这是最好的做法. (4认同)
  • 值得一提的是上面的代码不起作用 - operator <只接受一个参数.```operator <(const MyStruct&rhs)``` (2认同)
  • 对于大型结构和 c++1y,您可以添加一个函数 `auto AsTuple(const MyStruct &amp; s) { return std::tie(sx, sy); }`。这避免了在 `operator&lt;` 中重复结构的字段......不幸的是,我没有看到在 c++11 中这样做。 (2认同)
  • @Renaud在C ++ 11中,您可以使用lambda(`auto as_tuple = [](MyStruct const&s){return std :: tie(sx,sy);};`),因为这可以推断出返回类型。 (2认同)

Mik*_*our 19

其他人提到boost::tuple,它给你一个字典比较.如果要将其保留为具有命名元素的结构,可以创建临时元组以进行比较:

bool operator<(const MyStruct& x, const MyStruct& y)
{
    return boost::make_tuple(x.a,x.b,x.c) < boost::make_tuple(y.a,y.b,y.c);
}
Run Code Online (Sandbox Code Playgroud)

在C++ 0x中,这变成了std::make_tuple().

更新:现在,C++ 11就可以在std::tie()不复制对象的情况下创建引用元组.有关详细信息,请参阅Konrad Rudolph的新答案.


Ben*_*oit 9

我会这样做:

#define COMPARE(x) if((x) < (rhs.x)) return true; \
                   if((x) > (rhs.x)) return false;
COMPARE(a)
COMPARE(b)
COMPARE(c)
return false;
#undef COMPARE
Run Code Online (Sandbox Code Playgroud)

  • 只是那种模板无法替代的东西,因为你需要从封闭函数返回.一个建议:将`(x)>(rhs.x)`替换为`(rhs.x)<(x)`以仅依赖于成员的`operator <`.另外我认为括号是多余的,我无法看到这个宏如何与需要它们的输入一起正常工作. (5认同)
  • 我将取代最后的'COMPARE(c); return false;`with` return c <rhs.c`,以避免无关的>比较. (4认同)

Ste*_*end 6

在这种情况下,您可以使用boost::tuple<int, int, int>- 其运算符<按您想要的方式工作.


bja*_*fly 5

我认为最简单的方法是在所有比较中都使用 < 运算符,不要使用 > 或 ==。以下是我遵循的模式,您可以遵循所有结构

typedef struct X
{
    int a;
    std::string b;
    int c;
    std::string d;

    bool operator <( const X& rhs ) const
    {
        if (a < rhs.a) { return true; }
        else if ( rhs.a < a ) { return false; }

        // if neither of the above were true then 
        // we are consdidered equal using strict weak ordering
        // so we move on to compare the next item in the struct

        if (b < rhs.b) { return true; }
        if ( rhs.b < b ) { return false; }

        if (c < rhs.c) { return true; }
        if ( rhs.c < c ) { return false; }

        if (d < rhs.d) { return true; }
        if ( rhs.d < d ) { return false; }

        // if both are completely equal (based on strict weak ordering)
        // then just return false since equality doesn't yield less than
        return false;
    }
};
Run Code Online (Sandbox Code Playgroud)