const和非const类型的部分std :: hash特化

时间:2014-09-02 14:10:35

标签: c++ c++11 hash stdhash

我遇到一些代码在我的某个类中对std::hash进行部分特化时遇到了问题。这是一个自包含的例子。

编辑: 感谢Piotr,我更改了代码以包含修复程序,但错误仍然存​​在。

#include <functional>
#include <string>
#include <unordered_set>
#include <unordered_map>

class Base
{
public:
  template <class T>
  using const_pset = std::unordered_set<const T *, std::hash <T *>, std::equal_to <T *> >;
  template <class T, class U>
  using const_pmap = std::unordered_map<const T *, U, std::hash <T *>, std::equal_to <T *> >;
};

class A : public Base
{
public:
  std::size_t hash () const
  {
    std::hash<std::string> hashfn;
    return hashfn (str);
  }
  bool operator== (const A &a) const { return str == a.str; }
  std::string str;
};

namespace std
{
    template <>
    struct hash <A *>
    {
      typedef A argument_type;
      typedef std::size_t result_type;

      result_type operator () (const argument_type *op) const
      {
    return op->hash ();
      }
    };
    template <>
    struct hash <const A *>
    {
      typedef A argument_type;
      typedef std::size_t result_type;

      result_type operator () (const argument_type *op) const
      {
    return op->hash ();
      }
    };
};

extern const A* get_a ();

typedef Base::const_pmap<A, Base::const_pset<A> > mapA;

int
work (mapA &mapa)
{
  const A *a = get_a ();
  mapa[a];
  return 0;
}

如果用(g ++ 4.9.0)编译它:

$ g++ -std=gnu++11 -Wall -c test.cc 2>&1 | head -n 50
In file included from /tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable.h:35:0,
                 from /tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/unordered_set:47,
                 from test.cc:3:
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable_policy.h: In instantiation of 'static bool std::__detail::_Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, true>::_S_equals(const _Equal&, const _ExtractKey&, const _Key&, _HashCodeType, std::__detail::_Hash_node<_Value, true>*) [with _Key = const A*; _Value = std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<A*>; _HashCodeType = long unsigned int]':
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable_policy.h:1707:23:   required from 'bool std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::_M_equals(const _Key&, std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__hash_code, std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__node_type*) const [with _Key = const A*; _Value = std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<A*>; _H1 = std::hash<A*>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _Traits = std::__detail::_Hashtable_traits<true, false, true>; std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__hash_code = long unsigned int; std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__node_type = std::__detail::_Hash_node<std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >, true>]'
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable.h:1391:4:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base* std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_find_before_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type, const key_type&, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code) const [with _Key = const A*; _Value = std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >; _Alloc = std::allocator<std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<A*>; _H1 = std::hash<A*>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base = std::__detail::_Hash_node_base; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = const A*; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code = long unsigned int]'
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable.h:590:65:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type* std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_find_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type, const key_type&, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code) const [with _Key = const A*; _Value = std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >; _Alloc = std::allocator<std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<A*>; _H1 = std::hash<A*>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type = std::__detail::_Hash_node<std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >, true>; typename _Traits::__hash_cached = std::integral_constant<bool, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = const A*; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code = long unsigned int]'
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable_policy.h:597:60:   required from 'std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](const key_type&) [with _Key = const A*; _Pair = std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > >; _Alloc = std::allocator<std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > > >; _Equal = std::equal_to<A*>; _H1 = std::hash<A*>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> >; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = const A*]'
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/unordered_map.h:627:20:   required from 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type&) [with _Key = const A*; _Tp = std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> >; _Hash = std::hash<A*>; _Pred = std::equal_to<A*>; _Alloc = std::allocator<std::pair<const A* const, std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> > > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = std::unordered_set<const A*, std::hash<A*>, std::equal_to<A*>, std::allocator<const A*> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = const A*]'
test.cc:61:9:   required from here
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable_policy.h:1326:74: error: invalid conversion from 'const A*' to 'A*' [-fpermissive]
     { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v())); }
                                                                          ^
In file included from /tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/functional:49:0,
                 from test.cc:1:
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/stl_function.h:339:7: note: initializing argument 1 of 'bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A*]'
       operator()(const _Tp& __x, const _Tp& __y) const
       ^
In file included from /tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable.h:35:0,
                 from /tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/unordered_set:47,
                 from test.cc:3:
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/hashtable_policy.h:1326:74: error: invalid conversion from 'type {aka const A*}' to 'A*' [-fpermissive]
     { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v())); }
                                                                          ^
In file included from /tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/functional:49:0,
                 from test.cc:1:
/tools/oss/packages/x86_64-rhel5/gcc/4.9.0/include/c++/4.9.0/bits/stl_function.h:339:7: note: initializing argument 2 of 'bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A*]'
       operator()(const _Tp& __x, const _Tp& __y) const
       ^

我无法理解为什么会得到:error: invalid conversion from 'const A*' to 'A*' [-fpermissive]。 有关改进代码的任何建议吗?考虑到模板体是相同的,必须专门为Aconst A设置哈希值似乎很奇怪。

2 个答案:

答案 0 :(得分:1)

抱歉,我注意到我需要在std :: hash和std :: equal_to参数中添加const:

template <class T, class U>
  using const_pmap = std::unordered_map<const T *, U, std::hash <const T *>, std::equal_to <const T *> >

我仍然很乐意收到有关改进代码的答案。

答案 1 :(得分:1)

您为A编写了专门化,但是您将其与A*一起使用,因此您需要:

namespace std
{
    template <>
    struct hash<A*>
    {
      typedef const A* argument_type;
      typedef std::size_t result_type;

      result_type operator () (const argument_type op) const
      {
            return op->hash ();
      }
    };   
}

您的std::unordered_map适用于const A*

template <class T, class U>
using const_pmap = std::unordered_map<const T *, U, std::hash <T *>, std::equal_to <const T *> >;

但是,由于equal_to默认调用operator==,实际上你不需要它(除非你想专门化它):

class Base
{
public:
  template <class T>
  using const_pset = std::unordered_set<const T *, std::hash <T *> >;
  template <class T, class U>
  using const_pmap = std::unordered_map<const T *, U, std::hash <T *>>;
};

Compiled Demo

相关问题