不完整成员类型的哈希函数
hash function for incomplete member type
我有一个 class A
,它有一个无序容器,其中包含 class 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<B>
,它本身需要 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&>()))>
您的代码中有太多错误,无法提供有效示例,但这将帮助您入门。
有很多方法可以做到这一点,但在我看来,最干净的方法是通过 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;
}
我有一个 class A
,它有一个无序容器,其中包含 class 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<B>
,它本身需要 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&>()))>
您的代码中有太多错误,无法提供有效示例,但这将帮助您入门。
有很多方法可以做到这一点,但在我看来,最干净的方法是通过 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;
}