简体   繁体   English

std :: sort with custom comparator

[英]std::sort with custom comparator

In the following code, why do all three IntComparator() , IntComparator2 and IntComparator3 work as the 3rd parameter of the sort() function? 在下面的代码中,为什么所有三个IntComparator()IntComparator2IntComparator3都作为sort()函数的第三个参数? Wouldn't they have different l-value function types? 他们不会有不同的l值函数类型吗? Based on https://en.cppreference.com/w/cpp/algorithm/sort it says 基于https://en.cppreference.com/w/cpp/algorithm/sort,它说

The signature of the comparison function should be equivalent to the following: 比较函数的签名应等效于以下内容:

bool cmp(const Type1 &a, const Type2 &b); bool cmp(const Type1&a,const Type2&b);

which seems to match IntComparator2 better? 哪个似乎更符合IntComparator2

Also which one would be preferable? 还有哪一个更好? Third option seems much simpler and more intuitive. 第三种选择似乎更简单,更直观。


#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

struct IntComparator
{
  bool operator()(const int &a, const int &b) const
  {
    return a < b;
  }
};

bool IntComparator2 (const int &a, const int &b)
{
    return a < b;
}

bool IntComparator3 (int a, int b)
{
    return a < b;
}

int main()
{
    int items[] = { 4, 3, 1, 2 };
    std::sort(items, items+4, IntComparator());

    for (int n=0; n<4; n++) {
        std::cout << items[n] << ", ";
    }

    std::cout << "\n";

    int items2[] = { 4, 3, 1, 2 };
    std::sort(items2, items2+4, IntComparator2);

    for (int n=0; n<4; n++) {
        std::cout << items2[n] << ", ";
    }

    std::cout << "\n";

    int items3[] = { 4, 3, 1, 2 };
    std::sort(items3, items3+4, IntComparator3);

    for (int n=0; n<4; n++) {
        std::cout << items3[n] << ", ";
    }

    std::cout << "\n";

    return 0;
}

std::sort accepts a functor . std::sort接受一个functor This is any object that can be called (with the correct parameters). 这是可以调用的任何对象(使用正确的参数)。 The function achieves this by using templates, like the following 该功能通过使用模板实现此目的,如下所示

template<typename Iter, typename Comp>
void sort(Iter begin, Iter end, Comp compare) { ... }

IntComparator1 , 2, and 3 are all valid functors for this comparator, since they can all be called using operator() with 2 integers. IntComparator1和3都是这个比较器的有效函子,因为它们都可以使用带有2个整数的operator()来调用。

Also like you said, the third option is indeed usually more intuitive. 也像你说的那样,第三种选择确实通常更直观。

The sort() function will just call the comparator function you provided when a comparison is needed. sort()函数只需调用您在需要比较时提供的比较器函数。 The way your comparator gets its parameters (value, reference, const ref) is not the concern of sort() , it will call it the same way (passing two arguments of the same type) no matter how your comparator gets its parameters internally. 比较器获取其参数(value,reference,const ref)的方式不是sort()的关注点,无论比较器如何在内部获取其参数,它都将以相同的方式调用它(传递两个相同类型的参数)。
It is imperceptible from outside the comparator definition since the way we call you three functions is exactly the same. 从比较器定义之外看不到它,因为我们称之为三个函数的方式完全相同。

The only thing that is requested is that the comparator takes only two arguments and they must be of the same type of the elements to be sorted. 唯一要求的是比较器只接受两个参数,它们必须是要排序的元素的相同类型。

But, passing by const ref is better because your comparator guarantees to not modify the paramaters it compares, and also that it avoids useless copies (performance gain). 但是,通过const ref更好是因为你的比较器保证不修改它比较的参数,并且它避免了无用的副本(性能增益)。 That is why they have written should be equivalent (which is different of must be equivalent ). 这就是为什么他们写的应该是等价的 (不同的必须是等价的 )。

They are equivalent because the C++ specification says they both match the requirements of a binary predicate. 它们是等价的,因为C ++规范说它们都符合二元谓词的要求。 The following extracts seem relevant. 以下摘录似乎相关。

[function.objects] [function.objects]

20.14.1 A function object type is an object type that can be the type of the postfix-expression in a function call ([expr.call], [over.match.call]).224 A function object is an object of a function object type. 20.14.1函数对象类型是一种对象类型,它可以是函数调用中的postfix-expression的类型([expr.call],[over.match.call])。224函数对象是一个对象。功能对象类型。 In the places where one would expect to pass a pointer to a function to an algorithmic template, the interface is specified to accept a function object. 在人们期望将指向函数的指针传递给算法模板的地方,指定接口接受函数对象。 This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects. 这不仅使算法模板与函数指针一起使用,而且使它们能够使用任意函数对象。

[alg.sorting] [alg.sorting]

25.7.2 Compare is a function object type ([function.objects]) that meets the requirements for a template parameter named BinaryPredicate ([algorithms.requirements]) . 25.7.2 Compare是一个函数对象类型([function.objects]),它满足名为BinaryPredicate([algorithms.requirements])的模板参数的要求 The return value of the function call operation applied to an object of type Compare, when contextually converted to bool ([conv]), yields true if the first argument of the call is less than the second, and false otherwise. 当上下文转换为bool([conv])时,应用于Compare类型的对象的函数调用操作的返回值,如果调用的第一个参数小于第二个参数,则返回true,否则返回false。 Compare comp is used throughout for algorithms assuming an ordering relation. 比较comp用于假设有序关系的算法。

[algorithms.requirements] [algorithms.requirements]

25.2.8 When not otherwise constrained, the BinaryPredicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type T when T is part of the signature returns a value testable as true. 25.2.8如果没有其他约束,只要算法需要一个函数对象,当应用于取消引用两个相应迭代器的结果或解除引用迭代器并且当T是签名的一部分时键入T,则返回值testable时使用BinaryPredicate参数是的。 In other words, if an algorithm takes BinaryPredicate binary_pred as its argument and first1 and first2 as its iterator arguments with respective value types T1 and T2, it should work correctly in the construct binary_pred(*first1, *first2) contextually converted to bool ([conv]). 换句话说,如果算法将BinaryPredicate binary_pred作为其参数,并将first1和first2作为其迭代器参数以及相应的值类型T1和T2,则它应该在构造binary_pred(* first1,* first2)中正确转换为bool([ CONV])。 Unless otherwise specified, BinaryPredicate always takes the first iterator's value_type as its first argument, that is, in those cases when T value is part of the signature, it should work correctly in the construct binary_pred(*first1, value) contextually converted to bool ([conv]). 除非另有说明,否则BinaryPredicate总是将第一个迭代器的value_type作为其第一个参数,也就是说,在T值是签名的一部分的情况下,它应该在构造binary_pred(* first1,value)中正确地在上下文中转换为bool( [CONV])。 binary_pred shall not apply any non-constant function through the dereferenced iterators. binary_pred不应通过解除引用的迭代器应用任何非常量函数。 Given a glvalue u of type (possibly const) T1 that designates the same object as *first1, and a glvalue v of type (possibly const) T2 that designates the same object as *first2, binary_pred(u, *first2), binary_pred(*first1, v), and binary_pred(u, v) shall each be a valid expression that is equal to binary_pred(*first1, *first2) , and binary_pred(u, value) shall be a valid expression that is equal to binary_pred(*first1, value). 给定一个glvalue u类型(可能是const)T1指定与* first1相同的对象,glvalue v指定类型(可能是const)T2指定与* first2相同的对象,binary_pred(u,* first2),binary_pred( * first1,v)和binary_pred(u,v)应各自是一个等于binary_pred(* first1,* first2)的有效表达式,而binary_pred(u,value)应该是一个等于binary_pred的有效表达式( * first1,value)。

As to the question on which is preferable, I'd say that is opinion based, unless in your specific case profiling shows one to be better. 至于哪个更好的问题,我会说这是基于意见的,除非在你的具体情况下,分析表明一个更好。

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

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