我有一个如下所示的自定义类标识符,需要帮助来理解由于为自定义用户类标识符定义哈希函数而出现的编译时错误。该类如下所示
struct Identifier {
Identifier(const std::string &domain,
const std::string &name,
const std::string &version)
: domain(domain), name(name), version(version) {}
/// The domain associated with the identifier.
std::string domain;
/// The name associated with the identifier.
std::string name;
/// The version associated with the identifier.
std::string version;
};
inline bool operator==(const Identifier& lhs, const Identifier& rhs){
return ((lhs.domain == rhs.domain) && (lhs.name == rhs.name) && (lhs.version == rhs.version));
}
我有一个依赖于Identifier的接口ModuleInterface.h,如下
class ModuleInterface {
public:
using Identifiers = std::unordered_set<Identifier>;
virtual Identifiers getSupportedIdentifiers() = 0;
};
有一个 Manager 类,它有一个 registerModule 方法,该方法接受如下所示的 ModuleInterfaces
class Manager{
public:
bool registerModule(const std::shared_ptr<ModuleInterface> &module);
private:
std::map<Identifier, std::shared_ptr<ModuleInterface>> m_requestHandlers;
};
Manager.cpp类的实现如下
bool Manager::registerModule(const std::shared_ptr<ModuleInterface>& module){
/*
for(auto& requestIdentifier : module->getSupportedIdentifiers()){
//m_requestHandlers[requestIdentifier] = module;
} */
for (auto itr = module->getSupportedIdentifiers().begin(); itr != module->getSupportedIdentifiers().end(); ++itr) {
m_requestHandlers[*itr] = module;
}
return true;
}
现在,当我尝试编译它时,我看到编译时错误,错误如下所示
foo/src/Manager.cpp:17:21: warning: object backing the pointer will be destroyed at the end of the full-expression [-Wdangling-gsl]
for (auto itr = module->getSupportedIdentifiers().begin(); itr != module->getSupportedIdentifiers().end(); ++itr) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from foo/src/Manager.cpp:2:
In file included from foo/include/Registration/Manager.h:10:
In file included from bar/usr/include/c++/v1/map:550:
In file included from bar/usr/include/c++/v1/functional:515:
In file included from bar/usr/include/c++/v1/__functional/boyer_moore_searcher.h:25:
In file included from bar/usr/include/c++/v1/unordered_map:523:
bar/usr/include/c++/v1/__hash_table:838:5: error: static assertion failed due to requirement 'integral_constant<bool, false>::value': the specified hash does not meet the Hash requirements
static_assert(__check_hash_requirements<_Key, _Hash>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bar/usr/include/c++/v1/__hash_table:853:1: note: in instantiation of template class 'std::__enforce_unordered_container_requirements<Identifier, std::hash<Identifier>, std::equal_to<Identifier>>' requested here
typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type
^
bar/usr/include/c++/v1/unordered_set:614:30: note: while substituting explicitly-specified template arguments into function template '__diagnose_unordered_container_requirements'
static_assert(sizeof(__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), "");
^
foo/src/Manager.cpp:17:29: note: in instantiation of member function 'std::unordered_set<Identifier>::~unordered_set' requested here
for (auto itr = module->getSupportedIdentifiers().begin(); itr != module->getSupportedIdentifiers().end(); ++itr) {
^
1 warning and 1 error generated.
ninja: build stopped: subcommand f
任何理解我所缺少的内容的帮助或指示都将不胜感激,因为我不明白为什么哈希方法不满足要求,因为它将返回基于 lhs 和 rhs 的 bool 值。
它与指针或您的
Manager
或 ModuleInterface
设计无关。问题归结为:
struct Identifier {
// side note: better to take args by value, and then std::move
Identifier(const std::string &d, const std::string &n,
const std::string &v)
: domain(d), name(n), version(v) {}
std::string domain;
std::string name;
std::string version;
auto operator<=>(const Identifier&) const = default; // to avoid boilerplate code, since C++20
};
// this is OK
std::map<Identifier, int> myMap; // value type doesn't really matter here
// this will not compile
std::unordered_set<Identifier> mySet;
std::map
键的比较器是std::less<Key>
,因此在您的情况下是std::less<Identifier>
,可以通过默认比较运算符轻松处理。
另一方面,
std::unordered_set
需要std::equal_to<Key>
(你有)和std::hash<Key>
(你没有)。使您的 Identifier
“可哈希”的简单方法之一是简单地从 cppreference中复制粘贴注入
std::hash
中的
namespace std
的自定义特化示例:
template<>
struct std::hash<Identifier>
{
std::size_t operator()(const Identifier& id) const noexcept
{
std::size_t h1 = std::hash<std::string>{}(id.domain);
std::size_t h2 = std::hash<std::string>{}(id.name);
std::size_t h3 = std::hash<std::string>{}(id.version);
return h1 ^ (h2 << 1) ^ (h3 << 2);
}
};