Comparison object being invocable as const
当我尝试运行以下代码时,带有-std = c ++ 17的clang(6.0)和g ++(8)都给我一个static_assert错误:
1 2 3 4 5 6 7 8 9 10 11 | #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: error: static_assert failed due to requirement 'is_invocable_v'"comparison object must be invocable as const"
lang6.0
/usr/include/c++/8/bits/stl_tree.h:457:21: error: static assertion failed: comparison object must be invocable as const
将const作为operator()签名的一部分可以解决此问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #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类内部声明的每个对象都不会被修改(可变对象除外),那么为什么要这样做呢?
这是静态断言失败的源代码中的源代码:
1 2 3 4 5 6 7 8 9 10 | #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,其中"比较"对象从仅
我已经根据源代码注释找到了此链接,但是我仍然不明白为什么需要这样做。
这实际上不是答案,而是一个说明性的示例:
假设您有一个例程来测试您的集合是否包含特定值:
1 2 3 | template <typename T> bool contains(const std::set< T > &s, const T& value) { return s.find(value) != s.end(); } |
如果您的比较函子不能作为const调用,则将无法编译,并显示可怕的错误消息。 (即使在C ++ 11和14中)
使操作符为const(应如此)(不允许处于可变状态):
1 | struct ProcessComparator { inline bool operator()(const A&, const A&) const { return true; } }; |
如果跨线程并行运行此比较器,则constness安全性很好。默认情况下,它还可以防止产生怪异的副作用,并允许编译器进行更多优化。如果stdlib允许运算符为非常量,则还应假定存在某些状态被修改(非const),因此访问可能不是线程安全的,或者可能不会故意复制(并行访问)。
虽然编译器可能会自己解决这个问题(但仅在内联的情况下),但库现在强制执行此操作以帮助您编写更正确,更惯用的代码。