比较对象可以作为const调用

Fil*_*ues 9 c++ stl c++17

当我尝试运行以下代码时,clang(6.0)和g ++(8)与-std = c ++ 17都会给我一个static_assert错误:

#include <set>
struct A {};

struct ProcessComparator { inline bool operator()(const A&, const A&) { return true; } };

int main(void)
{
    std::set<A, ProcessComparator> A_Set;

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

g ++ 8

/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_tree.h:457:7:错误:由于需求'is_invocable_v',static_assert失败"比较对象必须作为const调用"

铿锵6.0

/usr/include/c++/8/bits/stl_tree.h:457:21:错误:静态断言失败:比较对象必须作为const调用

将const作为operator()签名的一部分来修复此问题:

#include <set>

struct A {};

/* Add const as part of the operator's signature */
struct ProcessComparator { inline bool operator()(const A&, const A&) const { return true; } };

int main(void)
{
    std::set<A, ProcessComparator> A_Set;

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

与std = c ++ 14同时,clang和g ++中的错误消失了.

我的问题是在c ++ 17中为此改变了现在给出一个错误,为什么这里的const很重要?

const只保证在ProcessComparator类中声明的每个对象都不会被修改(除了那些具有可变性的对象),那么为什么这是一个要求呢?


这是静态断言失败的源代码的源代码:

#if __cplusplus >= 201103L
      static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
      "comparison object must be invocable with two arguments of key type");
# if __cplusplus >= 201703L
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2542. Missing const requirements for associative containers
      static_assert(is_invocable_v<const _Compare&, const _Key&, const _Key&>,
      "comparison object must be invocable as const");
# endif // C++17
#endif // C++11
Run Code Online (Sandbox Code Playgroud)

添加了新的static_assert其中比较对象是从刚换_Compare&<const _Compare&is_invocableis_invocable_v,虽然说,从我能理解,只是为了获得内联和constexpr 这里看到


我找到了这个链接,基于源代码注释,但我仍然无法理解为什么这是必需的.

Mac*_*cke 12

Make operator const, as it should be (no mutable state allowed):

struct ProcessComparator { inline bool operator()(const A&, const A&) const { return true; } };
Run Code Online (Sandbox Code Playgroud)

如果您跨线程并行运行此比较器,则常量性对于安全来说是很好的。默认情况下,它还可以防止奇怪的副作用,并允许编译器进行更多优化。如果 stdlib 允许操作符为非常量,它还应该假设有一些状态正在被修改(非常量),因此访问可能不是线程安全的,或者它可能不会随意复制(并行访问)。

虽然编译器可能会自己解决这个问题(但仅限于内联),但库强制执行此操作以帮助您编写更正确和惯用的代码。