为什么这个程序在 g++ 4.8.5 中会出现编译错误?

Why do I get a compilation error for this program in g++ 4.8.5?

我正在尝试解决 online judge 的问题,法官使用 g++ 4.8.5。

以下程序在我的机器 (g++ 8.2.0) 上编译正确 -std=c++11 -pedantic-errors:

#include <algorithm>

struct Task {
    int deadline;
    const bool operator<(const Task &o) {
        return deadline < o.deadline;
    }
};
Task tasks[] = {8, 4, 3, 5, 1, 2, 0, 7};

int main()
{
    std::sort(tasks, tasks + 8);
}

然而,法官给我以下错误:

In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from Main.cpp:1:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of '_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&) [with _RandomAccessIterator = Task*; _Tp = Task]':
/usr/include/c++/4.8/bits/stl_algo.h:2283:70: required from '_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Task*]' /usr/include/c++/4.8/bits/stl_algo.h:2315:54:
required from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = Task*; _Size = int]' /usr/include/c++/4.8/bits/stl_algo.h:5461:36:
required from 'void std::sort(_RAIter, _RAIter) [with _RAIter = Task*]' Main.cpp:15:23:
required from here /usr/include/c++/4.8/bits/stl_algo.h:2245:19:
error: passing 'const Task' as 'this' argument of 'const bool Task::operator<(const Task&)' discards qualifiers [-fpermissive]
    while (__pivot < *__last)
       ^

法官用-std=c++11 -O2 -lm编译。

g++ 4.8 不完全支持 C++11 吗?我该如何编译它?

const bool operator<(const Task &o) {

应该是

bool operator<(const Task &o) const {

return的值为const没有意义,作为比较运算符不需要修改*this.

错误消息显示 passing 'const Task' as 'this' argument of 'const bool Task::operator<(const Task&)' discards qualifiers,因此在 std::sort 的内部某处它试图在 const Task 对象上调用 operator<。您原来的 tasks 数组不是 const,所以这大概是因为 std::sort 正在调用一个带有 const Task & 的辅助函数(因为辅助函数不需要修改任何东西)。

调用失败,因为您的 operator< 未声明为 const(即可在 const 对象上调用)。

我不确定 g++ 8.2 有什么不同,但显然 std::sort 的实现已经改变,所以它不再在内部引用 const T 对象。

注意错误消息中的这一行

error: passing 'const Task' as 'this' argument of 'const bool Task::operator<(const Task&)' discards qualifiers

std::sort 期望对象的 operator< 不会修改对象本身。您需要通过显式将其标记为 const.

来表明您的比较运算符不会改变对象的状态这一事实

正确的版本应该是这样的

struct Task {
    int deadline;
    const bool operator<(const Task &o) const {
        return deadline < o.deadline;
    }
};

有关详细信息,请参阅此 link:Meaning of 'const' last in a function declaration of a class?

是的,GCC 4.8 确实支持 C++11 的大部分,从 2013 年可以看出 here. However, this seems to have been an error in GCC 4.8. The exact requirements of std::sort are located in Section 25.4 of this ISO specification

它注意到 operator< 的唯一要求是它实现了“strict weak ordering”。然后它继续通过其数学属性定义 "strict weak ordering"。 None 这似乎意味着 operator< 必须是常量,因为 GCC 4.8 试图强制。 operator< 可能会更改内部变量,并且仍然遵循规范,只要返回的布尔值构成 "strict weak ordering"。这可用于计算 std::sort 函数对每个变量进行的比较次数,从而允许更轻松地对 std::sort 进行基准测试,而不会出现未定义的行为(作为许多不同可能性的一个示例)。

使用 const 肯定是对 GCC 4.8 中 C++11 的原始实现的过度假设,并在以后的版本中得到纠正。

不幸的是,如果在线判断使用的是那个版本的GCC,你也无能为力。这里的其他答案指定了如何修复它(即,使您的成员函数为 const)。

深入研究 GCC 的历史,我们可以看到它在 2013 年 9 月 27 日被更改 here。这似乎是一个更大的重构,可能没有注意错综复杂的地方,但贡献者确实在几个方面删除了 const,所以它似乎是有意的。提交消息也不太有启发性。如果你愿意你可以给他发邮件,看看他是否记得 xD