所有子类的模板专门化
template specialization for all subclasses
我想定义一个c++模板专门化,应用于给定基类的所有子类。这可能吗?
特别地,我想对STL的hash<>这样做。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);
由于 c++ 11您可以将SFINAE与标准库enable_if和is_base_of一起使用来解决问题。
c++ 20使一个更简洁的解决方案成为可能——基本上相当于enable_if,它甚至(可选地)与CRTP一起工作
#include <concepts>
#include <functional>
#include <unordered_set> // just for demo in main()
template <class T>
class Base {};
class Derived final : public Base<Derived> {};
template<class T>
requires std::derived_from<T, Base<T>>
struct std::hash<T> {
// constexpr is optional
constexpr size_t operator() (const T& value) const noexcept {
return 0xDEADBEEF; // FIXME: do something better :)
}
};
int main() {
// If operator() weren't constexpr, this couldn't be a *static* assert
static_assert(std::hash<Derived>()(Derived {}) == 0xDEADBEEF);
std::unordered_set<Derived> usageTest;
return 0;
}
解决方案是使用SFINAE来决定是否允许根据类继承结构进行专门化。在Boost中,您可以使用enable_if
和is_base_of
来实现此功能。
- http://www.boost.org/doc/libs/1_47_0/libs/utility/enable_if.html
- http://www.boost.org/doc/libs/1_47_0/libs/type_traits/doc/html/boost_typetraits/reference/is_base_of.html
我已经尽力了:
template<>
struct hash<Sub> : hash<Base> {
};
我有点担心,我没有让operator()
虚拟,虽然。
我认为这是不可能的,因为基于比匹配类型更复杂的东西来做模板专门化的方法是c++ SFINAE,它需要第二个(虚拟)模板参数。不幸的是,std::hash
只接受一个模板参数,并且不允许创建具有两个模板参数的std::hash
的另一个版本。因此,如果您对Jayen的解决方案不满意,您可以创建自己的hash
类型:
#include <iostream>
#include <type_traits>
using namespace std;
class ParentClass {};
class ChildClass : public ParentClass {};
// SFINAE, if T is not a child of ParentClass, substitution will fail
// You can create specializations for the general case, for another base classes, etc.
template<typename T, typename=typename enable_if<is_base_of<ParentClass, T>::value, T>::type>
struct your_hash
{
size_t operator()(const T& value)
{
return 42;
}
};
int main()
{
ParentClass pc;
ChildClass cc;
cout<<your_hash<ParentClass>()(pc)<<"n";
cout<<your_hash<ChildClass>()(cc)<<"n";
}
相关文章:
- 继承期间显示未知行为的子类
- 通过指向指针数组的指针访问子类的属性
- 从父类方法返回子类对象
- c++, 在子类中,如何在没有对象的情况下访问父类的方法?
- 将父类对象强制转换为子类的问题
- 避免在C++中重复子类定义
- 将QOpenGLWidget子类转换为使用Metal而不是OpenGL的子类是否可行?
- 如何初始化矢量的模板化子类
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 有没有办法按值将纯抽象类的所有子类传递给 C++ 中的函数?
- 使用子类覆盖基类中定义的函数
- 子类地址等于虚拟基类地址?
- 将子类方法声明为基类的友元
- C++子类共享变量?
- 如何检查模板专用化是否是基本模板的子类?
- 仅让特定类'Fabric'构造类'Foo'及其所有子类的实例
- 使用模板参数重载C++方法:如何使其适用于模板的子类?
- 使用抽象类的子类专门化模板
- 所有子类的模板专门化
- 如何在子类中重载模板化函数(专门化)