vendredi 22 juillet 2016

Why this code provides specialization for **ALL** enums for std::hash template?

I'm not a pro in C++ but somehow I provided a solution while porting MSVS 2015 C++ code to MinGW 4.9.2 to specialize std::hash class to support all enums. It there's any C++ compiler developers or C++ pro programmers here, can you explain why this specialization works, although it is Undefined Behavior according the C++ standard they say?

Link for full code with samples on Gist

#include <unordered_set>
#include <functional>

#if (defined __GNUC__) && (__GNUC__ < 6)
// Adds support of std::hash<enum T> to libstdc++.
// GCC 6 provides it out of the box.
namespace std {
    template<typename T>
    struct hash {
        constexpr size_t operator()(typename std::enable_if<std::is_enum<T>::value, T>::type s) const noexcept {
            return static_cast<size_t>(s);
        }
    };
}
#endif

Providing support for std::hash<enum T> means that all classes like std::unordered_XXX will support any enum as a key.

GCC 6.1.0 fails with error

error: redefinition of 'struct std::hash<_Tp>'

GCC 5.3.0 without this std::hash definition fails for std::unordered_set with following error:

In file included from /usr/local/gcc-5.3.0/include/c++/5.3.0/bits/hashtable.h:35:0,
                 from /usr/local/gcc-5.3.0/include/c++/5.3.0/unordered_set:47,
                 from prog.cc:1:
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/hashtable_policy.h: In instantiation of 'struct std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> >':
/usr/local/gcc-5.3.0/include/c++/5.3.0/type_traits:137:12:   required from 'struct std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > >'
/usr/local/gcc-5.3.0/include/c++/5.3.0/type_traits:148:38:   required from 'struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:95:63:   required from 'class std::unordered_set<Foo>'
prog.cc:25:25:   required from here
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/hashtable_policy.h:85:34: error: no match for call to '(const std::hash<Foo>) (const Foo&)'
  noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
                                  ^
In file included from /usr/local/gcc-5.3.0/include/c++/5.3.0/bits/move.h:57:0,
                 from /usr/local/gcc-5.3.0/include/c++/5.3.0/bits/stl_pair.h:59,
                 from /usr/local/gcc-5.3.0/include/c++/5.3.0/utility:70,
                 from /usr/local/gcc-5.3.0/include/c++/5.3.0/unordered_set:38,
                 from prog.cc:1:
/usr/local/gcc-5.3.0/include/c++/5.3.0/type_traits: In instantiation of 'struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >':
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:95:63:   required from 'class std::unordered_set<Foo>'
prog.cc:25:25:   required from here
/usr/local/gcc-5.3.0/include/c++/5.3.0/type_traits:148:38: error: 'value' is not a member of 'std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > >'
     : public integral_constant<bool, !_Pp::value>
                                      ^
In file included from /usr/local/gcc-5.3.0/include/c++/5.3.0/unordered_set:48:0,
                 from prog.cc:1:
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h: In instantiation of 'class std::unordered_set<Foo>':
prog.cc:25:25:   required from here
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:95:63: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc>  _Hashtable;
                                                               ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:102:45: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::key_type key_type;
                                             ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:103:47: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::value_type value_type;
                                               ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:104:43: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::hasher hasher;
                                           ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:105:46: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::key_equal key_equal;
                                              ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:106:51: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::allocator_type allocator_type;
                                                   ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:111:45: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::pointer  pointer;
                                             ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:112:50: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::const_pointer const_pointer;
                                                  ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:113:47: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::reference  reference;
                                               ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:114:52: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::const_reference const_reference;
                                                    ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:115:46: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::iterator  iterator;
                                              ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:116:51: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::const_iterator const_iterator;
                                                   ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:117:51: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::local_iterator local_iterator;
                                                   ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:118:57: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::const_local_iterator const_local_iterator;
                                                         ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:119:47: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::size_type  size_type;
                                               ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:120:52: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       typedef typename _Hashtable::difference_type difference_type;
                                                    ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:274:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       operator=(initializer_list<value_type> __l)
       ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:368:2: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
  emplace(_Args&&... __args)
  ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:412:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       insert(const value_type& __x)
       ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:416:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       insert(value_type&& __x)
       ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:471:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       insert(initializer_list<value_type> __l)
       ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:616:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       equal_range(const key_type& __x)
       ^
/usr/local/gcc-5.3.0/include/c++/5.3.0/bits/unordered_set.h:620:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<Foo> >, std::__detail::__is_noexcept_hash<Foo, std::hash<Foo> > > >'
       equal_range(const key_type& __x) const
       ^

Aucun commentaire:

Enregistrer un commentaire