C++ 在实现std::hash时修改内部结构<;T>;
我正在编写一个自定义的C++ 在实现std::hash时修改内部结构<;T>;,c++,c++11,hash,constants,unordered-set,C++,C++11,Hash,Constants,Unordered Set,我正在编写一个自定义的OrderedTree类,我想用作无序集的键 在对树进行哈希运算时,我想做几件事: 惰性地计算散列并根据需要缓存它(因为这可能是一个昂贵的操作) 也许平衡一下这棵树 这两个操作都不会更改对象的语义相等或哈希值,但会修改一些私有字段 不幸的是,在std::hash::operator()内尝试修改OrderedTree中的任何成员似乎违反了unordered\u set所期望的常量正确性 我可以将我的OrderedTree与无序集一起使用吗?如果是,怎么做 编辑: 根据评论中
OrderedTree
类,我想用作无序集的键
在对树进行哈希运算时,我想做几件事:
惰性地计算散列并根据需要缓存它(因为这可能是一个昂贵的操作)
也许平衡一下这棵树
这两个操作都不会更改对象的语义相等或哈希值,但会修改一些私有字段
不幸的是,在std::hash::operator()
内尝试修改OrderedTree
中的任何成员似乎违反了unordered\u set
所期望的常量正确性
我可以将我的OrderedTree
与无序集一起使用吗?如果是,怎么做
编辑:
根据评论中的要求,最低限度的概念证明:
#include <unordered_set>
std::size_t hash_combine(std::size_t a, std::size_t b) {
// TODO: Copy from boost source or something
return 0;
}
struct Node {
int value;
Node *left, *right, *parent;
std::size_t hash(std::size_t seed) const {
if (left != nullptr)
seed = left->hash(seed);
std::hash<int> hasher;
seed = hash_combine(seed, hasher(value));
if (right != nullptr)
seed = right->hash(seed);
return seed;
}
};
struct Tree {
Tree(): hash_(0), root(nullptr) {}
Node *root;
std::size_t hash() const {
if (hash_ == 0 && root != nullptr) {
hash_ = root->hash(7);
}
return hash_;
}
private:
std::size_t hash_;
};
namespace std {
template<>
struct hash<Tree> {
std::size_t operator()(const Tree& t) const {
return t.hash();
}
};
}
int main() {
std::unordered_set<Tree> set;
}
可以保证,std容器在执行const
或逻辑const
操作时只调用const
成员。如果那些const
操作是多读卡器安全的,那么容器也是安全的;相反,如果不是,容器也不是
散列值的不变性和相等性(或可以保证std容器在执行const
或逻辑上const
操作时只调用const
成员。如果这些const
操作是多读卡器安全的,那么容器也是安全的;反之,如果不是,那么容器也不是安全的
哈希值和等式的不变性(或如何“似乎违反常量正确性”显化本身?这只是一些普遍的焦虑,或者你不知道如何实现它,或者你有编译器错误吗?听说过关键字“可变”吗?@JVApen我以前没有听说过。谢谢!这似乎正是我想要的。如果你用它来发布答案,我会接受的。@PeteBecker当我发布这个问题时,这一切都在我的脑海中,b但我会在一两分钟内尝试提出一个概念证明,“似乎违反了常量的正确性”是怎么回事显化本身?这只是一些普遍的焦虑,或者你不知道如何实现它,或者你有编译器错误吗?听说过关键字“可变”吗?@JVApen我以前没有听说过。谢谢!这似乎正是我想要的。如果你用它来发布答案,我会接受的。@PeteBecker当我发布这个问题时,这一切都在我的脑海中,b但我会尝试在一两分钟内提出一个概念证明当你说“一个使用强制转换来绕过…”时,你的意思是const\u cast
对吗?一个带有mutable
的程序仍然运行良好?我同意你对const
的态度,我不确定我是否真的会使用mutable
,但我想学习更多关于危险的特性,所以如果我真的需要,我可以使用它们。@mathconst\u cast
或等效的C型cast,是的。在声明的const
上违反const
(而不仅仅是const&
到非const
)UB.可变
成员在这个意义上不会违反常量
,即使在常量
方法中修改。当你说“使用强制转换绕过…”的常量方法时,你的意思是常量
对吗?具有可变
的程序仍然表现良好?我同意你对常量
的态度,并且我不确定我是否真的会使用mutable
,但我想了解更多关于危险特性的信息,以便在我真的需要时可以使用它们。@mathconst\u cast
或等效的C型cast,是的。在声明的const
上违反const
(不仅仅是常量&
到非常量
)是UB。可变
成员在这个意义上不会违反常量
,即使在常量
方法中修改。
Sample.cc:31:13: error: cannot assign to non-static data member within const member function 'hash'
hash_ = root->hash(7);
~~~~~ ^
Sample.cc:29:15: note: member function 'Tree::hash' is declared const here
std::size_t hash() const {
~~~~~~~~~~~~^~~~~~~~~~~~