Reputation: 26335
Since my example is somewhat complex, I have put a sample here that demonstrates the error (Code will be inlined below as well): http://coliru.stacked-crooked.com/a/a426995302bda656
#include <functional>
#include <unordered_map>
#include <memory>
enum class DeliveryMethodType
{
POST_MASTER,
BUBBLE,
};
class IDeliveryMethod
{
};
class BubbleDelivery : public IDeliveryMethod
{
};
template<typename Key, typename Interface>
class GenericFactory
{
public:
using FactoryMethod = std::function<std::unique_ptr<Interface> ()>;
static Key const& Register(Key const& key, FactoryMethod creator)
{
s_factoryMethods.insert({key, creator});
return key;
}
static std::unique_ptr<Interface> Create(Key const& key)
{
std::unique_ptr<Interface> obj;
auto it = s_factoryMethods.find(key);
if (it != s_factoryMethods.end())
{
obj = it->second();
}
return obj;
}
private:
static std::unordered_map<Key, FactoryMethod> s_factoryMethods;
};
template<typename Key, typename Interface>
std::unordered_map<Key, typename GenericFactory<Key, Interface>::FactoryMethod>
GenericFactory<Key, Interface>::s_factoryMethods;
using DeliveryMethodFactory = GenericFactory<DeliveryMethodType, IDeliveryMethod>;
static auto key = DeliveryMethodFactory::Register(DeliveryMethodType::BUBBLE, []() {
return std::unique_ptr<IDeliveryMethod>(new BubbleDelivery);
});
int main()
{
}
My design goal here is to create a generic static factory class. Each translation unit will (at static initialization time) invoke the Register()
method for a specific specialization of GenericFactory
for the desired key and factory method types.
I'm getting the following compiler error, which I'm not sure how to resolve.
error: implicit instantiation of undefined template 'std::hash<DeliveryMethodType>'
I imagine perhaps that my template trickery is failing here and I'm not doing something right. Can anyone help identify the issue here? Thanks.
Upvotes: 1
Views: 2277
Reputation: 254431
The key type for an unordered container needs either a specialisation of std::hash
defined for it, or a custom hash function provided to the container.
Since your container is in a template, with a generic key, it's tricky to provide a custom function; so provide a specialisation, for example:
namespace std {
template <> struct hash<DeliveryMethodType> {
size_t operator()(DeliveryMethodType x) const {
return hash<int>()(static_cast<int>(x));
}
};
}
Upvotes: 2
Reputation: 2745
For unordered_map
you have to provide a hash function for you user defined key-type either by providing a implementation of std::hash<DeliveryMethodType>
ob by providing your own hash-function as an constructor argument to unordered_map
.
Upvotes: 0
Reputation: 54138
unordered_map has a default third parameter which is the hasher for the class contained in the container. Sometimes there is a default implementation of this, eg. for int
or std::string
- if not, you have to implement this.
Upvotes: 0