简体   繁体   English

你如何编写一个operator()或者比trivalue-compare-function更少的函子

[英]How do you write a operator() or less-than-functor neater than a trivalue-compare-function

Writing an operator< () for a struct appears to be clearer than writing the classical trivalue compare. 为结构编写运算符<()似乎比编写经典的trivalue比较更清晰。

for example, to sort the following 例如,对以下内容进行排序

struct S {
    int val;
};

you can write an operator< () 你可以写一个运算符< ()

bool operator< ( const S &l, const S &r ) {
     return l.val < r.val;
}

or, a trivalue function ( usually in the following fashion ) 或者, 三值函数( 通常以下列方式

int compare( const S &l, const S &r ) {
    if( r.val > l.val ) return 1;
    if( r.val < l.val ) return -1;
    return 0;
}

The former is clearer, therefore you can say there's better code quality. 前者更清晰,因此可以说代码质量更好。 The latter forces you to think of 3 cases, which complicates code. 后者迫使你想到3个案例,这使代码变得复杂。

But this thought is a bit deceiving in more complex structures: 但是这个想法在更复杂的结构中有点欺骗:

struct S {
    int x;
    int y;
};

the following is clear, and begginners tend to write it like so 以下是明确的,并且begginners倾向于这样写

bool operator< ( const S &l, const S &r ) {
     if( l.x < r.x ) return true;
     if( l.y < r.y ) return true;
     return false;
}

but it's wrong ! 但这是错的 You can't sort correctly with this ! 你无法正确排序!

And it takes some time to think that you actually have to write it like so 并且认为你实际上必须这样写它需要一些时间

bool operator< ( const S &l, const S &r ) {
     if( l.x < r.x ) return true;
     if( l.x > r.x ) return false;
     if( l.y < r.y ) return true;
     if( l.y > r.y ) return false;
     return false;
}

for it to work correctly. 为了它正常工作。

Can you, and do you write this sort of compare function in a nicer/clearer manner ? 你可以,并且你是否以更好/更清晰的方式编写这种比较函数? The old trivalue compare function at least 'forced' you into thinking about >, <, and == cases. 旧的trivalue比较函数至少“强迫”你考虑>,<和==情况。

If I don't care about performance or compiler spew, I tend to use this: 如果我不关心性能或编译器,我倾向于使用:

return make_tuple(l.x, l.y, ...) < make_tuple(r.x, r.y, ...);

And for a slightly less expensive in terms of copies version: 而副本版本的价格略低:

return tie(cref(l.x), cref(l.y), ...) < tie(cref(r.x), cref(r.y), ...);

Incidentally, the second version also works with lvalues. 顺便提一下,第二个版本也适用于左值。

I like to do it like this: 我喜欢这样做:

bool operator< ( const S &l, const S &r )
{
    if( l.x != r.x ) return l.x < r.x;
    else return l.y < r.y;
}

EDIT: note that this is also one useful feature of std::pair too - it defines this already so you can't make the mistake. 编辑:请注意,这也是std::pair一个有用功能 - 它已经定义了这个,所以你不能犯这个错误。

In the int case you can simply write: int情况下,您可以简单地写:

return l.x < r.x || (l.x == r.x && l.y < r.y);

Only of you are talking about a type that doesn't have == with the correct behaviour do you need to use something more complex, even then it's not too bad. 只有你在谈论没有==具有正确行为的类型你需要使用更复杂的东西,即使这样也不算太糟糕。

return l.x < r.x || (!(r.x < l.x) && l.y < r.y);

Extending to more members: 扩展到更多成员:

return l.x < r.x ||
      !(r.x < l.x) && (l.y < r.y ||
      !(r.y < l.y) && (l.z < r.z ||
      /* ... */
      ) /* lisp-like sequence of ) */ );

If you can arrange your members to be in an array or other container you can use std::lexicographical_compare . 如果您可以将您的成员安排在数组或其他容器中,则可以使用std::lexicographical_compare

如果您使用以下命令自动生成所有运算符,那么只需声明一个三值比较函数就可以了: http//en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick

This is no clearer or shorter than your last example, but it does have the advantage of not requiring anything other than operator< on the members. 这比上一个示例更清晰或更短,但它确实具有除成员之外不需要任何operator<的优点。

bool operator< ( const S &l, const S &r ) { 
     if( l.x < r.x ) return true; 
     if( r.x < l.x ) return false; 
     if( l.y < r.y ) return true; 
     if( r.y < l.y ) return false; 
     return false; 
} 

The last case can always be simplified, unfortunately the prior cases must always be the longer form. 最后一种情况总是可以简化,不幸的是,先前的情况必须始终是较长的形式。

bool operator< ( const S &l, const S &r ) { 
     if( l.x < r.x ) return true; 
     if( r.x < l.x ) return false; 
     return  l.y < r.y; 
} 

One thing I did once which seemed a useful idiom was to write a compare function which returns a boolean given takes two arguments plus a boolean called "bias". 我做过一次似乎是一个有用的习惯用法的一件事是写一个比较函数,它返回一个给定两个参数的布尔值加上一个名为“bias”的布尔值。 The function returns true if the first argument is greater, or if "bias" is set and the two arguments are equal. 如果第一个参数更大,或者设置了“bias”且两个参数相等,则该函数返回true。 Thus, a compare whose result depended upon two sub-comparisons would be: 因此,其结果取决于两个子比较的比较将是:

if (compare(a.part1,b.part1,compare(a.part2,b.part2,bias)))
    ...

Note that this will do 'extra' comparisons, since part2's will be compared even if the part1 compare would be sufficient to yield an answer, but if avoids redundant tests for equality. 请注意,这将进行“额外”比较,因为即使part1比较足以产生答案,也将比较part2,但是如果避免冗余测试的相等性。

Otherwise, using tri-value logic, one could do something like: 否则,使用三值逻辑,可以执行以下操作:

int result;

  if ((result = compare(a.part1,b.part1)) != 0) return result;
  if ((result = compare(a.part2,b.part2)) != 0) return result;

The latter form avoids unnecessary comparisons, and is easily extensible to any number of fields. 后一种形式避免了不必要的比较,并且可以容易地扩展到任何数量的字段。

For the first tri-value compare() function 对于第一个三值 compare()函数

int compare( const S &l, const S &r ) {
    return r.val - l.val;
}

For the later 对于后来

bool operator< ( const S &l, const S &r ) {
     return (l.x < r.x) || ((l.x == r.x) && (l.y < r.y));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM