CRTP 在 std::hash 的基类方面为派生类提供专业化

问题描述 投票:0回答:1

TLDR

我正在尝试根据 CRTP 样式框架中的基类为一堆派生类编写一次模板专门化。但是,我无法编译它。

我正在努力做什么

我有一个基类,想要生成多种派生类。基类命名了一些将返回派生类类型的对象的方法。因此,我一直在使用 CRTP 模式来耦合两者(遗憾的是,C++23 的“推导这个”不是一个选项,因为在撰写本文时大多数编译器尚不支持它)。

我希望能够对这些对象进行哈希处理(这样我就可以将它们放入某些 STL 容器中),因此我尝试编写

std::hash
的专门化,但我遇到了困难。我可以根据派生类编写专门化的类,但无法弄清楚如何根据基类编写通用类。

代码

基类和派生类以及 CRTP

#include <vector>

template<typename Self>
class Base {
protected:
    using my_type = int;
    std::vector<my_type> bar; // <- I will be doing something special to hash this...

public:
    virtual void baz(void) const = 0;

    Self foo(void) const {
        Self result = *dynamic_cast<const Self *>(this);
        // do something with the private bar variable.
        return result;
    };
};

class Derived_A final : public Base<Derived_A> {
public:
    void baz(void) const override {}
};

class Derived_B : public Base<Derived_B> {
public:
    void baz(void) const override {}
};

我想如何使用这些

int main() {
    Derived_A d_a;
    Derived_B d_b;
    auto d_a_ = d_a.foo();
    d_a.baz();
    std::hash<Derived_B>{}(d_b);
    std::hash<Derived_A>{}(d_a); // <-- This doesn't compile
}

模板专业化

// Works. 
template<>
struct std::hash<Derived_B> {
    std::size_t operator()(const auto &shape) const noexcept { return 0; }
};

// Not working. 
template<typename Self>
struct std::hash<Base<Self>> {
    std::size_t operator()(const Base<Self> &shape) const noexcept { return 0; }
};

编译器说什么

error: call to deleted constructor of '__enum_hash<Derived_A>'
    std::hash<Derived_A>{}(d_a);
                         ^
/usr/local/opt/llvm/bin/../include/c++/v1/__functional/hash.h:643:5: note: '__enum_hash' has been explicitly marked deleted here
    __enum_hash() = delete;
c++ templates hash template-specialization crtp
1个回答
0
投票

您要找的是这个:

template<typename T> requires std::is_base_of_v<Base<T>, T>
struct std::hash<T> {
    std::size_t operator()(T const& shape) const noexcept { return 0; }
};

您可以匹配任何扩展

T
Base<T>

此外,您应该将

dynamic_cast<Self const*>(this)
更改为
static_cast<Self const*>
,因为您在编译时就知道转换是有效的。

© www.soinside.com 2019 - 2024. All rights reserved.