将枚举 class 的 std::pair 和 unordered_map 用作键的不完整类型结构 std::hash 的使用无效
Invalid use of incomplete type struct std::hash with unordered_map with std::pair of enum class as key
我想使用 unordered_map<std::pair<enum_class,other_enum_class>,std::uint8_t>
来管理一些像素图格式。
这里是最小代码:
#include <unordered_map>
#include <utility>
#include <cstdint>
#include <iostream>
#include <functional>
enum class PNM : std::uint8_t { PBM, PGM, PPM };
enum class Format : bool { BIN, ASCII };
struct pair_hash {
public:
template <typename T, typename U>
std::size_t operator()(const std::pair<T, U> &x) const {
return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
}
};
int main(){
std::unordered_map<std::pair<PNM, Format>, std::uint8_t, pair_hash> k_magic_number ({
{ { PNM::PBM, Format::BIN }, 1 }, { { PNM::PGM, Format::BIN }, 2 }, { { PNM::PPM, Format::BIN }, 3 },
{ { PNM::PBM, Format::ASCII }, 4 }, { { PNM::PGM, Format::ASCII }, 5 }, { { PNM::PPM, Format::ASCII }, 6 }
});
std::cout << k_magic_number[std::make_pair<PNM, Format>(PNM::PBM, Format::BIN)];
}
当我尝试实例化 class 时,使用 GCC 我有一个 error :
main.cpp:14:24: error: invalid use of incomplete type 'struct std::hash'
return std::hash()(x.first) ^ std::hash()(x.second);
In file included from
/usr/local/include/c++/5.2.0/bits/basic_string.h:5469:0,
from /usr/local/include/c++/5.2.0/string:52,
[...]
有了 Clang,我还有一个 error :
error: implicit instantiation of undefined template 'std::hash'
return std::hash()(x.first) ^ std::hash()(x.second);
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/hashtable_policy.h:1257:16:
note: in instantiation of function template specialization
'pair_hash::operator()' requested here
[...]
使用 VS2013 我没有错误,代码编译并执行。
我的代码中缺少什么?
g++-5 给出以下错误:
invalid use of incomplete type struct std::hash<PNM>
invalid use of incomplete type struct std::hash<Format>
因此,您应该只将 std::hash
专门化为 PNM
和 Format
。
namespace std {
template<>
struct hash<PNM>
{
typedef PNR argument_type;
typedef size_t result_type;
result_type operator () (const argument_type& x) const
{
using type = typename std::underlying_type<argument_type>::type;
return std::hash<type>()(static_cast<type>(x));
}
};
template<>
struct hash<Format>
{
typedef Format argument_type;
typedef size_t result_type;
result_type operator () (const argument_type& x) const
{
using type = typename std::underlying_type<argument_type>::type;
return std::hash<type>()(static_cast<type>(x));
}
};
}
或者您可以编写模板结构,它仅适用于 enums
使用 SFINAE(不确定,它不是标准的 UB,因为它实际上不是专门化的)。
namespace std
{
template<typename E>
struct hash
{
typedef E argument_type;
typedef size_t result_type;
using sfinae = typename std::enable_if<std::is_enum<E>::value>::type;
result_type operator() (const E& e) const
{
using base_t = typename std::underlying_type<E>::type;
return std::hash<base_t>()(static_cast<base_t>(e));
}
};
}
我想使用 unordered_map<std::pair<enum_class,other_enum_class>,std::uint8_t>
来管理一些像素图格式。
这里是最小代码:
#include <unordered_map>
#include <utility>
#include <cstdint>
#include <iostream>
#include <functional>
enum class PNM : std::uint8_t { PBM, PGM, PPM };
enum class Format : bool { BIN, ASCII };
struct pair_hash {
public:
template <typename T, typename U>
std::size_t operator()(const std::pair<T, U> &x) const {
return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
}
};
int main(){
std::unordered_map<std::pair<PNM, Format>, std::uint8_t, pair_hash> k_magic_number ({
{ { PNM::PBM, Format::BIN }, 1 }, { { PNM::PGM, Format::BIN }, 2 }, { { PNM::PPM, Format::BIN }, 3 },
{ { PNM::PBM, Format::ASCII }, 4 }, { { PNM::PGM, Format::ASCII }, 5 }, { { PNM::PPM, Format::ASCII }, 6 }
});
std::cout << k_magic_number[std::make_pair<PNM, Format>(PNM::PBM, Format::BIN)];
}
当我尝试实例化 class 时,使用 GCC 我有一个 error :
main.cpp:14:24: error: invalid use of incomplete type 'struct std::hash'
return std::hash()(x.first) ^ std::hash()(x.second);
In file included from
/usr/local/include/c++/5.2.0/bits/basic_string.h:5469:0,
from /usr/local/include/c++/5.2.0/string:52,
[...]
有了 Clang,我还有一个 error :
error: implicit instantiation of undefined template 'std::hash' return std::hash()(x.first) ^ std::hash()(x.second); /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/hashtable_policy.h:1257:16: note: in instantiation of function template specialization 'pair_hash::operator()' requested here [...]
使用 VS2013 我没有错误,代码编译并执行。
我的代码中缺少什么?
g++-5 给出以下错误:
invalid use of incomplete type
struct std::hash<PNM>
invalid use of incomplete type
struct std::hash<Format>
因此,您应该只将 std::hash
专门化为 PNM
和 Format
。
namespace std {
template<>
struct hash<PNM>
{
typedef PNR argument_type;
typedef size_t result_type;
result_type operator () (const argument_type& x) const
{
using type = typename std::underlying_type<argument_type>::type;
return std::hash<type>()(static_cast<type>(x));
}
};
template<>
struct hash<Format>
{
typedef Format argument_type;
typedef size_t result_type;
result_type operator () (const argument_type& x) const
{
using type = typename std::underlying_type<argument_type>::type;
return std::hash<type>()(static_cast<type>(x));
}
};
}
或者您可以编写模板结构,它仅适用于 enums
使用 SFINAE(不确定,它不是标准的 UB,因为它实际上不是专门化的)。
namespace std
{
template<typename E>
struct hash
{
typedef E argument_type;
typedef size_t result_type;
using sfinae = typename std::enable_if<std::is_enum<E>::value>::type;
result_type operator() (const E& e) const
{
using base_t = typename std::underlying_type<E>::type;
return std::hash<base_t>()(static_cast<base_t>(e));
}
};
}