所有子类的模板专门化
我想定义一个适用于给定基类的所有子类的 C++ 模板专业化。这可能吗?
特别是,我想对 STL 的 hash<> 执行此操作。散列<>被定义为一个空的参数化模板,以及一系列针对特定类型的专业化:
template<class _Key>
struct hash { };
template<>
struct hash<char>
{
size_t
operator()(char __x) const
{ return __x; }
};
template<>
struct hash<int>
{
size_t
operator()(int __x) const
{ return __x; }
};
...
我想定义这样的东西:
template<class Base>
struct hash {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
class Sub : public Base {
public:
size_t my_hash() const { ... }
};
并能够像这样使用它:
hash_multiset<Sub> set_of_sub;
set_of_sub.insert(sub);
但是,我的哈希模板与 STL 中的通用模板冲突。有没有一种方法(也许使用特征)来定义适用于给定基类的所有子类的模板专业化(无需修改STL定义)?
请注意,我知道只要需要此哈希专业化,我就可以使用一些额外的模板参数来完成此操作,但如果可能的话,我想避免这种情况:
template<>
struct hash<Base> {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
....
// similar specialization of equal_to is needed here... I'm glossing over that...
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub;
set_of_sub.insert(sub);
I would like to define a C++ template specialization that applies to all subclasses of a given base class. Is this possible?
In particular, I'd like to do this for STL's hash<>. hash<> is defined as an empty parametrized template, and a family of specializations for specific types:
template<class _Key>
struct hash { };
template<>
struct hash<char>
{
size_t
operator()(char __x) const
{ return __x; }
};
template<>
struct hash<int>
{
size_t
operator()(int __x) const
{ return __x; }
};
...
I would like to define something like this:
template<class Base>
struct hash {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
class Sub : public Base {
public:
size_t my_hash() const { ... }
};
and be able to use it like this:
hash_multiset<Sub> set_of_sub;
set_of_sub.insert(sub);
However, my hash template conflicts with the generic one from STL. Is there a way (perhaps using traits) to define a template specialization that applies to all subclasses of a given base class (without modifying the STL definitions)?
Note that I know I can do this with some extra template parameters whenever this hash specialization is needed, but I'd like to avoid this if possible:
template<>
struct hash<Base> {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
....
// similar specialization of equal_to is needed here... I'm glossing over that...
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub;
set_of_sub.insert(sub);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
从 C++ 11 开始,您可以将 SFINAE 与标准库 enable_if 和 is_base_of 来解决问题。
Since C++ 11 you can use SFINAE together with standard library enable_if and is_base_of to solve the problem.
C++20 使更清晰的解决方案成为可能 - 基本上等同于enable_if,它甚至(可选)与 CRTP 一起使用
C++20 makes a cleaner solution possible - basically equivalent to enable_if, which even (optionally) works with CRTP
解决方案是使用 SFINAE 根据类继承结构来决定是否允许您的专业化。在 Boost 中,您可以使用
enable_if
和is_base_of
来实现这一点。The solution is to use SFINAE to decide whether or not to allow your specialisation depending on the class inheritance structure. In Boost you can use
enable_if
andis_base_of
to implement this.这是我能做的最好的事情:
不过,我有点担心我不必将
operator()
设为虚拟。This was the best I could do:
I'm a little worried that I didn't have to make
operator()
virtual, though.我认为这是不可能的,因为基于比仅匹配类型更复杂的东西来进行模板专业化的方法是 C++ SFINAE,它需要第二个(虚拟)模板参数。不幸的是,std::hash 只接受一个模板参数,并且不允许使用两个模板参数创建另一版本的 std::hash 。因此,如果您对 Jayen 的解决方案不满意,您可以可以创建您自己的
hash
类型:I don't think it is possible, because the way to do template specialization based on something more complex than just matching the type is C++ SFINAE, which requires second (dummy) template argument. Unfortunatelly,
std::hash
takes only one template argument and it is not allowed to create another version ofstd::hash
with two template arguments. Therefore, the if you aren't satisfied with Jayen's solution, you can create your ownhash
type: