1

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.

4
  • Successfully compiled with c++14. Commented Mar 26, 2015 at 17:23
  • @MaxFomichev That can't be possible since my coliru link is using -std=c++14 Commented Mar 26, 2015 at 17:37
  • Why are you sure? bash-3.2$ c++ -c -std=c++1y ./main.cpp bash-3.2$ c++ -v Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn) Target: x86_64-apple-darwin14.1.0 Thread model: posix Commented Mar 26, 2015 at 21:20
  • sorry for formatting in my previous message. Your code is successfully compiled by clang 3.5. But, probably, it's c++17 extension. Commented Mar 26, 2015 at 21:52

3 Answers 3

2

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));
        }
    };
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is it necessary (or even legal) to insert the hash specialization into the std namespace? Or can I put it in my own namespace and rely on ADL?
It's necessary because the default hash type is std::hash<T> (although you could specify your own type, and override that for every key type you want to support, if you prefer). It's legal to declare template specialisations in std as long as they involve a user-defined type. ADL only works on functions; std::hash is a class template.
0

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.