STD ::与自定义比较器进行排序

std::sort with custom comparator

本文关键字:排序 自定义 STD 比较器      更新时间:2023-10-16

在以下代码中,为什么所有三个IntComparator()IntComparator2IntComparator3都可以作为sort()函数的第三参数工作?它们不会具有不同的L值函数类型吗?基于https://en.cppreference.com/w/cpp/algorithm/sort说

比较函数的签名应等于 以下:

bool cmp(const type1& a,const type2& b(;

哪个似乎更好地匹配IntComparator2

另外哪一个是可取的?第三个选项似乎更简单,更直观。


#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接受 functor。这是任何可以调用的对象(具有正确的参数(。该函数通过使用模板来实现此功能,例如以下

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

IntComparator1、2和3都是此比较器的有效函数,因为它们都可以使用2个整数使用Operator((来调用。

也像您说的那样,第三种选择通常更直观。

sort()函数将在需要比较时调用您提供的比较函数。比较器获取其参数的方式(值,参考,const Ref(不是sort()的关注点,它将以相同的方式称其为相同的方式(通过同一类型的两个参数(,无论您的比较器如何在内部获得其参数。<<br/>从比较器的定义外,这是无法察觉的,因为我们称您为您的三个函数的方式完全相同。

唯一要求的是比较器仅采用两个参数,它们必须是要分类的元素的类型。

但是,通过const ref的传递是更好的,因为您的比较器保证不会修改其比较的参数,并且还避免了无用的副本(性能增益(。这就是为什么他们已经写了应该等效的(的不同,必须等效(。

它们是等效的,因为C 规范说它们都符合二进制谓词的要求。以下摘录似乎很重要。

[function.Objects]

20.14.1函数对象类型是一种对象类型,可以是函数呼叫中的后缀示例类型([[expr.call],[over.match.call](。224函数对象是一个功能对象类型的对象。在人们期望将指针传递给函数到算法模板的地方,指定接口以接受函数对象。这不仅使算法模板与函数的指针一起使用,还使它们可以使用任意函数对象。

[alg.sorting]

25.7.2 比较是函数对象类型([[function.Objects](,它符合名为binaryPredicate([algorithms.requirements](的模板参数要求的要求。将函数调用操作的返回值应用于类型对象,如果上下文将上下文转换为bool([cons](时,如果呼叫的第一个参数小于第二个参数,则会产生真实,否则为false。假设有序关系的整个算法都使用了比较comp。

[算法替代]

25.2.8如果不另行约束,则每当算法期望将函数对象应用于验证两个相应的迭代器或放弃迭代器或type t时,当the t t t t t是签名回报的一部分时值可测试的值。换句话说,如果一种算法将二进制predicate biary_pred作为其参数,而first1 and first2则作为其迭代剂参数,具有相应的值类型T1和T2,则应在构造binary_pred( *first1, *first2(中正常工作([ *first1, *first2(([[[[cons](。除非另有说明,否则二进制prodicate始终将第一个迭代器的value_type作为其第一个参数,也就是说,在t值是签名的一部分时,它应在构造binary_pred(*first1,value(中正确工作(*first1,value(上下文转换为bool([cons](。binary_pred不得通过启用的迭代器应用任何非恒定功能。给定一个类型的glvalue u(可能是const(t1,该t1指定与 *first1相同的对象,而类型(可能是const(t2的glvalue v则指定与 *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(。

关于哪个是最好的问题,我会说这是基于意见的,除非在您的特定案例分析中表明一个更好。