0

As stated in the title, I am having trouble getting the VC++ compiler to work when using a two-dimensional map with a user-defined class as a key. Here is the map I am trying to declare:

std::unordered_map<tag, std::map<tag, std::pair<bool, bool>>> transitRights;

And here are the declarations of class tag and the specialisation of the std::hash function:

class tag
{
public:
 tag();
 tag(const char[3]);
 tag(const std::string&);
 void operator=(const tag&);
 const bool operator==(const tag&)const;
 operator const std::string()const;
 const char& getA()const { return a; }
 const char& getB()const { return b; }
 const char& getC()const { return c; }
private:
 char a, b, c;
};
namespace std
{
 template<> class hash<tag>
 {
 public:
 size_t operator()(const tag& _tag) const
 {
 return hash<char>()(_tag.getA()) ^ hash<char>()(_tag.getB()) ^ hash<char>()(_tag.getC());
 }
 };
};

When attempting to compile, Visual Studio throws a bunch of these cryptic error messages at me:

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(600): error C2664: 'std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)' : cannot convert argument 1 from 'const tag' to 'const std::pair<const _Kty,_Ty> &'
1> with
1> [
1> _Kty=int
1> , _Ty=std::pair<bool,bool>
1> ]
1> Reason: cannot convert from 'const tag' to 'const std::pair<const _Kty,_Ty>'
1> with
1> [
1> _Kty=int
1> , _Ty=std::pair<bool,bool>
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(723) : see reference to function template instantiation 'void std::allocator<_Other>::construct<_Objty,const tag&>(_Objty *,const tag &)' being compiled
1> with
1> [
1> _Other=std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>
1> , _Objty=std::pair<const int,std::pair<bool,bool>>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(723) : see reference to function template instantiation 'void std::allocator<_Other>::construct<_Objty,const tag&>(_Objty *,const tag &)' being compiled
1> with
1> [
1> _Other=std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>
1> , _Objty=std::pair<const int,std::pair<bool,bool>>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(872) : see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,const tag&>(std::allocator<_Other> &,_Objty *,const tag &)' being compiled
1> with
1> [
1> _Alloc=std::allocator<std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>>
1> , _Ty=std::pair<const int,std::pair<bool,bool>>
1> , _Other=std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>
1> , _Objty=std::pair<const int,std::pair<bool,bool>>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(872) : see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,const tag&>(std::allocator<_Other> &,_Objty *,const tag &)' being compiled
1> with
1> [
1> _Alloc=std::allocator<std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>>
1> , _Ty=std::pair<const int,std::pair<bool,bool>>
1> , _Other=std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>
1> , _Objty=std::pair<const int,std::pair<bool,bool>>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(933) : see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Other>>::construct<_Ty,const tag&>(_Ty *,const tag &)' being compiled
1> with
1> [
1> _Other=std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>
1> , _Ty=std::pair<const int,std::pair<bool,bool>>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(933) : see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Other>>::construct<_Ty,const tag&>(_Ty *,const tag &)' being compiled
1> with
1> [
1> _Other=std::_Tree_node<std::pair<const int,std::pair<bool,bool>>,void *>
1> , _Ty=std::pair<const int,std::pair<bool,bool>>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(1176) : see reference to function template instantiation 'std::_Tree_node<std::pair<const _Kty,_Ty>,void *> *std::_Tree_buy<std::pair<const _Kty,_Ty>,std::allocator<std::pair<const _Kty,_Ty>>>::_Buynode<const tag&>(const tag &)' being compiled
1> with
1> [
1> _Kty=int
1> , _Ty=std::pair<bool,bool>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(1176) : see reference to function template instantiation 'std::_Tree_node<std::pair<const _Kty,_Ty>,void *> *std::_Tree_buy<std::pair<const _Kty,_Ty>,std::allocator<std::pair<const _Kty,_Ty>>>::_Buynode<const tag&>(const tag &)' being compiled
1> with
1> [
1> _Kty=int
1> , _Ty=std::pair<bool,bool>
1> ]
1> nation.cpp(600) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::emplace<const tag&>(const tag &)' being compiled
1> with
1> [
1> _Kty=int
1> , _Ty=std::pair<bool,bool>
1> , _Pr=std::less<int>
1> , _Alloc=std::allocator<std::pair<const int,std::pair<bool,bool>>>
1> ]
1> nation.cpp(600) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::emplace<const tag&>(const tag &)' being compiled
1> with
1> [
1> _Kty=int
1> , _Ty=std::pair<bool,bool>
1> , _Pr=std::less<int>
1> , _Alloc=std::allocator<std::pair<const int,std::pair<bool,bool>>>
1> ]

Any insight into what I am doing wrong here would be greatly appreaciated.

asked Nov 9, 2015 at 20:44

2 Answers 2

2

The problem is that the nested object is a std::map (not an unordered_map) and for that you need a less-than comparison for tag.

You should be able to build an unordered_map of unordered_maps, however.

answered Nov 9, 2015 at 20:55
Sign up to request clarification or add additional context in comments.

Comments

1

The hash must be a struct:

namespace std {
 template<> struct hash<tag> {
 ^^^^^^
 public:
 size_t operator()(const tag& _tag) const {
 return hash<char>()(_tag.getA()) ^ hash<char>()(_tag.getB()) ^ hash<char>()(_tag.getC());
 }
 };
};

Edit:

As @6502 correctly mentioned, you will also have to define a less than operator< because you're using also a std::map with key tag (example below):

bool operator<(tag const &t1, tag const &t2) {
 return t1.getA() < t2.getA(); 
}

LIVE DEMO

answered Nov 9, 2015 at 20:49

2 Comments

The code will compile only if you don't actually use the transitRights object but will stop working as soon as you try to use it unless you make it an unorederd_map<tag, unordered_map<... instead of using map for the outer map value.
@StefanDimitrov std::map is an ordered container and needs to know how tag objects compare with each other in order to attain that order. However, you'll also have to change from class to struct as shown.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.