有条件地将 std::hash 特化为 std::shared_ptr 结构
Conditionally specialize std::hash for std::shared_ptr struct
我有一个基地class。目标是强制将 std::hash 专门化为 std::shared_ptr 以及从 Base 继承的所有 classes。
我尝试了以下使用虚拟模板参数的方法,但编译器错误显然抱怨这是 struct std::hash<std::shared_ptr<_Tp>>
.
的重新定义
class Base {
};
class Derived : public Base {
};
namespace std {
template<typename T,
typename std::enable_if<std::is_base_of<Base, T>::value, Base>::type* = nullptr
>
struct hash<std::shared_ptr<T>> {
size_t operator()(const std::shared_ptr<T>& d) const {
return 616;
}
};
}
我的问题是:是否可以像这样有条件地专门化 std
class?
您问题中的代码的问题不是它是重定义,而是偏特化中不允许使用默认模板参数,并且偏特化中的所有模板参数都必须是可推导的。
std::hash
没有在主模板中提供可用于 SFINAE 的第二个模板参数,但基于 你可以做这样的事情作为解决方法:
#include <memory>
#include <utility>
class Base {};
class Derived : public Base {};
template <typename First, typename... Others>
using first = First;
namespace std {
template <typename T>
struct hash<first<std::shared_ptr<T>,
std::enable_if_t<std::is_base_of_v<Base, T>>>> {
size_t operator()(const std::shared_ptr<T>& d) const { return 616; }
};
} // namespace std
我认为原则上是可以的,因为声明取决于用户定义的类型 Base
。
关于此专业化是否应被视为 std::shared_ptr
标准专业化的重新定义,标准中存在未解决的问题。 (GCC 认为不是,Clang 认为是。)
但更重要的是,您仍然会遇到此部分专业化并不比标准为 std::shared_ptr
提供的部分专业化更专业的问题。因此,任何实际使用都会导致歧义错误,我认为没有任何方法可以使专业化更加专业化。
因此我认为您唯一的解决方案是为每个派生类型定义 std::hash
的显式特化,也许借助于宏。或者(可能更合适)您应该编写自己的哈希仿函数,并在需要时提供它作为 std::hash
的替代方法。
我有一个基地class。目标是强制将 std::hash 专门化为 std::shared_ptr 以及从 Base 继承的所有 classes。
我尝试了以下使用虚拟模板参数的方法,但编译器错误显然抱怨这是 struct std::hash<std::shared_ptr<_Tp>>
.
class Base {
};
class Derived : public Base {
};
namespace std {
template<typename T,
typename std::enable_if<std::is_base_of<Base, T>::value, Base>::type* = nullptr
>
struct hash<std::shared_ptr<T>> {
size_t operator()(const std::shared_ptr<T>& d) const {
return 616;
}
};
}
我的问题是:是否可以像这样有条件地专门化 std
class?
您问题中的代码的问题不是它是重定义,而是偏特化中不允许使用默认模板参数,并且偏特化中的所有模板参数都必须是可推导的。
std::hash
没有在主模板中提供可用于 SFINAE 的第二个模板参数,但基于
#include <memory>
#include <utility>
class Base {};
class Derived : public Base {};
template <typename First, typename... Others>
using first = First;
namespace std {
template <typename T>
struct hash<first<std::shared_ptr<T>,
std::enable_if_t<std::is_base_of_v<Base, T>>>> {
size_t operator()(const std::shared_ptr<T>& d) const { return 616; }
};
} // namespace std
我认为原则上是可以的,因为声明取决于用户定义的类型 Base
。
关于此专业化是否应被视为 std::shared_ptr
标准专业化的重新定义,标准中存在未解决的问题。 (GCC 认为不是,Clang 认为是。)
但更重要的是,您仍然会遇到此部分专业化并不比标准为 std::shared_ptr
提供的部分专业化更专业的问题。因此,任何实际使用都会导致歧义错误,我认为没有任何方法可以使专业化更加专业化。
因此我认为您唯一的解决方案是为每个派生类型定义 std::hash
的显式特化,也许借助于宏。或者(可能更合适)您应该编写自己的哈希仿函数,并在需要时提供它作为 std::hash
的替代方法。