比较对象可作为const调用

时间:2018-07-08 19:29:46

标签: c++ stl c++17

当我尝试运行以下代码时,带有(-std = c ++ 17)的clang(6.0)和g ++(8)都给我一个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;
}

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;
}

同时使用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

添加了一个新的static_assert,其中“比较”对象从_Compare&<更改为const _Compare&,从is_invocable更改为is_invocable_v,尽管据我所知,只是为了获得内联和constexpr as seen here


我已经根据源代码注释找到了this链接,但我仍然不明白为什么这是必需的。

2 个答案:

答案 0 :(得分:2)

这实际上不是答案,而是一个说明性的示例:

假设您有一个例程来测试您的集合中是否包含特定值:

template <typename T>
bool contains(const std::set<T> &s, const T& value)
{ return s.find(value) != s.end(); }

如果您的比较函子不能作为const调用,则将无法编译,并显示可怕的错误消息。 (甚至在C ++ 11和14中)

答案 1 :(得分:-1)

使运算符const保持应有的状态(不允许处于可变状态):

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

如果跨线程并行运行此比较器,则constness安全性很好。默认情况下,它还可以防止怪异的副作用,并允许编译器进行更多优化。如果stdlib允许运算符为非常量,则还应假定存在某些状态已被修改(非常量),因此访问可能不是线程安全的,或者可能不会故意复制(并行访问)。

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