【问题标题】:Why do I get a compilation error for this program in g++ 4.8.5?为什么我在 g++ 4.8.5 中收到此程序的编译错误?
【发布时间】:2018-10-05 20:51:44
【问题描述】:

我正在尝试解决来自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 吗?这个怎么编译?

【问题讨论】:

    标签: c++11 g++4.8


    【解决方案1】:

    是的,GCC 4.8 确实支持大部分 C++11,可以看到 here。但是,这似乎是 GCC 4.8 中的一个错误。从 2013 年开始,std::sort 的确切要求位于此 ISO specification 的第 25.4 节。

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

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

    很遗憾,如果在线法官使用的是该版本的 GCC,您将无能为力。此处的其他答案指定了如何修复它(即,使您的成员函数为 const)。

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

    【讨论】:

    • 事实上,它似乎也不意味着它返回一个布尔值。它只检查a &lt; b != false 的值,根据其定义“上下文转换为布尔值”。
    【解决方案2】:
    const bool operator<(const Task &o) {
    

    应该是

    bool operator<(const Task &o) const {
    

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

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

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

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

    【讨论】:

      【解决方案3】:

      注意错误信息中的这一行

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

      std::sort 期望您的对象的 operator&lt; 不会修改对象本身。您需要通过显式将其标记为 const 来表明您的比较运算符不会改变对象的状态。

      正确的版本看起来像

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

      有关更多信息,请参阅此链接:Meaning of 'const' last in a function declaration of a class?

      【讨论】:

      • 他的问题更多是关于为什么 g++ 4.8 与 g++ 8 不同,我认为这两个答案都不能回答原始问题。如果错了,g++ 8不应该失败吗?
      猜你喜欢
      • 2012-03-13
      • 2015-01-28
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 1970-01-01
      相关资源
      最近更新 更多