可作为常量调用的比较对象
Comparison object being invocable as const
当我尝试运行以下代码时,带有 -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"比较对象必须可作为 const 调用",static_assert失败
叮当 6.0
/usr/include/c++/8/bits/stl_tree.h:457:21:错误:静态断言失败:比较对象必须可作为常量调用
将 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 只保证在 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,如图所示
我已经根据源代码注释找到了这个链接,但我仍然不明白为什么需要这样做。
使运算符 const,因为它应该是(不允许可变状态(:
struct ProcessComparator { inline bool operator()(const A&, const A&) const { return true; } };
如果跨线程并行运行此比较器,则恒常性对于安全性非常有用。默认情况下,它还可以防止可能导致问题的副作用,并允许编译器进一步优化内容。如果 stdlib 允许运算符是非常量,它还应该假设存在某种状态被修改(非常量(,因此访问可能不是线程安全的,或者它可能不会随意复制(并行访问(。
虽然编译器可能可以自己解决这个问题(但只有在内联的情况下(,但库强制执行这一点是为了帮助你编写更正确和更惯用的代码。
更新
如果您尝试聪明地在比较运算符中缓存指向对象的指针以在多次比较相同的对象时进行更快的比较(请参阅 f.ex. 小于许多排序操作(,则可能会发生这种情况。
这不是一个真正的答案,而是一个说明性的例子:
假设您有一个例程来测试您的集合是否包含特定值:
template <typename T>
bool contains(const std::set<T> &s, const T& value)
{ return s.find(value) != s.end(); }
如果您的比较函子不能作为 const 调用,那么这将无法编译并显示可怕的错误消息。(即使在C++11和14(
- 对于BTreeMap和其他依赖于Ord的东西,是否有等效于C++比较器对象?
- C++ <algorithm> 使用对象作为比较定义的 sort()
- C++,如何使用常量对象和非常量对象进行比较?
- 绘制一个对象,比较模具缓冲区的两个不同值
- 隐式转换为比较函数对象(函子)用于 std::sort 而不是 std::map?
- 为什么地图需要实现'operator<'以及如何比较对象?
- 如何使用std::lower_bound比较对象变量,而不使用第二个对象进行比较
- 可作为常量调用的比较对象
- 如何为C++映射创建自己的字符串比较对象
- 如何用类别的consumetrized构造函数声明使用类的比较对象设置的STL设置
- 我可以防止 std::sort 复制传递的比较对象吗?
- 是否可以创建一个函数来比较对象向量中动态选择的变量
- 比较对象的3个数字属性
- 如何将比较对象或函数传递给类函数
- C++STL priority_queue,比较对象的方法
- 比较对象标识符与字符串
- c++ STL集合:比较对象与外部状态
- 比较对象和指针
- 比较对象的两个向量的元素
- c++比较对象