为啥 std::stable_sort() 的比较器函数的参数必须设置为常量?

Posted

技术标签:

【中文标题】为啥 std::stable_sort() 的比较器函数的参数必须设置为常量?【英文标题】:Why arguments of comparator function of std::stable_sort() must be set constants?为什么 std::stable_sort() 的比较器函数的参数必须设置为常量? 【发布时间】:2020-05-19 13:41:27 【问题描述】:

各位程序员大家好,我正在解决一个需要以稳定顺序排序的 leetcode 问题。

问题链接:https://leetcode.com/problems/rearrange-words-in-a-sentence/submissions/

我注意到 std::stable_sort() 的比较器函数的参数必须设置为常量,否则会产生以下编译时错误。

下面是产生编译时错误的代码:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void display(vector<string> &a);
bool compare(string &s1, string &s2);

int main() 
    vector<string> a = "abc", "defgh", "ijk";

    // sorting vector<string> in stable order
    // error will be generated
    std::stable_sort(a.begin(), a.end(), compare);
    display(a);
    return 0;


// argument strings should be made constants???
bool compare(string &s1, string &s2) 
    return s1.length() < s2.length();


void display(vector<string> &a) 
    for(int i=0; i<=a.size()-1; i++) 
        cout << a[i] << " ";
    
    cout << "\n";
    return ;


// errors generated
/*
    error: binding reference of type ‘std::__cxx11::basic_string<char>&’ to ‘const 
    std::__cxx11::basic_string<char>’ discards qualifiers
    177 |   return bool(_M_comp(*__it, __val)); 

    error: binding reference of type ‘std::__cxx11::basic_string<char>&’ to ‘const 
    std::__cxx11::basic_string<char>’ discards qualifiers
    215 |   return bool(_M_comp(__val, *__it)); 
*/

我尝试了谷歌搜索,但找不到任何东西。我搜索了 Stack Overflow 并遇到了一个问题,但无法理解那里解释的原因。

堆栈溢出答案链接:

https://***.com/a/45905608/13331053

感谢任何帮助。提前致谢!

【问题讨论】:

函数签名(由返回类型和函数参数产生的函数类型)与 std::stable_sort() 期望/接受的自定义谓词不匹配。它需要一个函数(或函子),其中有两个对 const 类型(在您的情况下为 const std::string&amp;)和返回类型 bool 的引用。您的 compare() 函数根本不适合这个预期的签名,但如果您将其更改为 bool compare(const string &amp;s1, const string &amp;s2),它会。 好的,我明白了。但设计决策背后的原因可能是什么?因为std::sort() 函数不需要其比较器函数的参数是常量。 因为 std::sort() 函数不需要其比较器函数的参数是常量。 你确定吗? AFAIK、std::sort()std::stable_sort() 对自定义谓词有相同的要求。 std::sort():比较函数的签名应该等价于:bool cmp(const Type1 &amp;a, const Type2 &amp;b); 没错。这是由于实现方式的不同。 【参考方案1】:

因为这是函数所需要的。引用std::stable_sort 上的 cppreference(强调我的):

比较函数的签名应该等价于:

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

虽然签名不需要const &amp;,但该函数不得修改传递给它的对象,并且必须能够接受所有类型的值(可能是constType1Type2,无论值类别(因此,Type1 &amp; 是不允许的[,Type1 也不允许,除非 Type1 的移动等同于复制(C++11 起)])。

您的函数必须接受const 参数,并且非常量引用类型不满足此要求。因此,您的 compare 函数应如下所示:

bool compare(const string &s1, const string &s2);

GCC 可以接受 std::sort 中的非 const 版本:https://godbolt.org/z/S2tL44,尽管 std::sort 具有与 std::stable_sort 完全相同的要求。我假设它根本没有在任何地方检查,std::sort 实现不依赖于常量,但std::stable_sort 确实如此。为什么?这将是源代码(或标准库维护者)的问题。

在任何情况下,始终在此类函数中使用const&amp; 参数以让编译器捕获对对象的任何意外修改并确保它适用于每个编译器,这样会更安全、更便携。

【讨论】:

以上是关于为啥 std::stable_sort() 的比较器函数的参数必须设置为常量?的主要内容,如果未能解决你的问题,请参考以下文章

浮点数比较为啥没有相等的函数

Linq Orderby 与自身进行比较。为啥?

为啥数学库经常被 FLOPS 比较?

为啥比较 char 变量两次比比较短变量一次快

为啥 Java 类应该实现可比较的?

为啥数组使用'==='运算符来比较元素?