【问题标题】:hash function for incomplete member type不完整成员类型的哈希函数
【发布时间】:2016-01-10 06:49:32
【问题描述】:

我有一个类A,它有一个带有类B 实例的无序容器,B 依赖于A,因为它有一个指向其A 实例的指针作为字段。我可以在执行A之前转发声明B,但这还不够,因为A中的无序容器需要std::hash<B>的定义,而hover不能在A之前定义,因为它依赖于它。

template <typename X>
class B;

namespace std
{
    
    template <typename V>
    struct hash<B<V>>  // <- requires full definition
    {
        size_t operator()(const B<V>& b) const
        {
           return (b.mem /*do hashing stuff with it*/ );
        }
    };
    
}


template <typename T>
class A
{

typedef A<T> THIS;
    
    void func()
    {
    }
    
    std::unordered_set<B<THIS>>  set;// <- requires std::hash<B>
};


template <typename A>
class B
{
    B(A* a)
    {
        A_ptr = a;
    }
    
    void otherfunc()
    {
        A_ptr->func();
    }
    
public:

    int mem;
    A* A_ptr;
};

有没有办法解决这个问题?

B需要A 才能完成。 A不需要B是完整的,但它需要std::hash&lt;B&gt;,它本身需要B是完整的。

编辑:

我试图将 Richard Hodges 的提议合并到我的实际程序中,但我无法让它发挥作用。这是代码在我的文件中编译的顺序:

namespace E
{
    
    template<typename G>
    class R;
    
    template <typename V, typename P>
    class G;
    
}

namespace std
{
    template <typename G> std::size_t hash_code(const E::R<G>&);
    
    
    template <typename G>
    struct hash<E::R<G>>
    {
        size_t operator()(const E::R<G>& r) const
        {
            return hash_code(r);
        }
    };
}

namespace E
{
  
    template <typename V, typename P>
    class G
    {
        // code
    }

    template <typename G>
    class R
    {
        // code
    }

}


namespace std
{
    template<typename G>
    size_t hash_code(const E::R<G>& r)
    {
        size_t hash = 0x9e3779b9;
        
        typename E::R<G>::Rside v = r[0];
        
        for(auto t = v.begin(); t != v.end(); ++t)
        {
            hash += (((*t + (hash << 6)) ^ (hash >> 16)) - hash);
        }
        v = r[1];
        
        for(auto t = v.begin(); t != v.end(); ++t)
        {
            hash += (((*t + (hash << 6)) ^ (hash << 16)) - hash);
        }
        return hash;
        
    }
}

但我得到了

implicit instantiation of undefined template
      'std::__1::hash<std::__1::vector<std::__1::vector<int, std::__1::allocator<int>
      >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > >'
    : public integral_constant<bool, __is_empty(_Tp)> {};

/usr/include/c++/5.2.0/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >) (const std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&)’
  noexcept(declval<const _Hash&>()(declval<const _Key&>()))>

【问题讨论】:

  • 转发声明A,声明B,声明A?
  • 你在 B 类中的 mem 变量是私有的,它不能作为 b.mem 访问
  • 它不应该工作。该细节与实际问题无关。
  • @NathanOliver 但 B 要求 A 是完整的,因为它访问它。
  • 如果B里面的A是模板参数,则与class A无关。那么真正的问题是什么?

标签: c++ hash dependencies


【解决方案1】:

您的代码中有太多错误,无法提供一个有效的示例,但这将帮助您入门。

有很多方法可以做到这一点,但在我看来,最干净的方法是通过 ADL 找到的名为 hash_code 的免费函数。

类似这样的:

// forward declarations
template <typename X> class B;
template <typename X> std::size_t hash_code(const B<X>&);

// specialisation of std::hash, uses only references so forward declarations are fine.    
template <typename V>
struct std::hash<B<V>>  // <- no longer requires full definition
{
    size_t operator()(const B<V>& b) const {
        return hash_code(b);
    }
};

...
... later on ...
...

// provide the definition of hash_code once B has been defined.
template<typename A>
std::size_t hash_code(const B<A>& b) {
    return b.mem;
}

【讨论】:

  • 谢谢,我试过你的建议,但我猜它有问题。我已经用它编辑了我的startpost。
  • hash_code 不应位于 std 命名空间中。它应该与其参数在同一个命名空间中。在你的情况下,E。建议您快速谷歌搜索argument dependent lookup (ADL)。读一遍,想一想,然后再读一遍。需要一段时间才能沉浸其中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-04
  • 1970-01-01
  • 2021-07-25
  • 2019-09-25
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多