0

我有一个基类。目标是强制使用从 Base 继承的所有类为 std::shared_ptr 专门化 std::hash。

我已经使用虚拟模板参数尝试了以下方法,但编译器错误显然抱怨这是对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开设这样的课程?

4

1 回答 1

1

您问题中代码的问题不在于它是重新定义,而是部分专业化中不允许默认模板参数,并且部分专业化中的所有模板参数都必须是可推导出的。

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需要它的替代方案。

于 2020-04-10T16:23:44.067 回答