Using std :: reference_wrapper as a key in std :: map

I have a bunch of objects in the class hierarchy and would like to make std::map using the references to these objects as keys on the map. It seems that std::reference_wrapper will be exactly what you need for this, but I can't get it to work. What I have tried so far:

 class Object { // base class of my hierarchy // most details unimportant public virtual bool operator< (const Object &) const; // comparison operator }; std::map<std::reference_wrapper<const Object>, int> table; auto it = table.find(object); table[object] = 42; table[object]++ 

However, I always get some unclear errors from the compiler:

 /usr/include/c++/4.5.3/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = std::reference_wrapper<const Object>]': /usr/include/c++/4.5.3/bits/stl_tree.h:1522:38: instantiated from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::find(const _Key&) [with _Key = std::reference_wrapper<const Object>, _Val = std::pair<const std::reference_wrapper<const Object>, int>, _KeyOfValue = std::_Select1st<std::pair<const std::reference_wrapper<const Object>, int> >, _Compare = std::less<std::reference_wrapper<const Object> >, _Alloc = std::allocator<std::pair<const std::reference_wrapper<const Object>, int> >, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const std::reference_wrapper<const Object>, int> >]' /usr/include/c++/4.5.3/bits/stl_map.h:697:29: instantiated from 'std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&)[with _Key = std::reference_wrapper<const Object>, _Tp = int, _Compare = std::less<std::reference_wrapper<const Object> >, _Alloc = std::allocator<std::pair<const std::reference_wrapper<const Object>, int> >, std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const std::reference_wrapper<const Object>, int> >, key_type = std::reference_wrapper<const Object>]' testfile.cpp:39:31: instantiated from here /include/c++/4.5.3/bits/stl_function.h:230:22: error: no match for 'operator<' in '__x < __y' 

The error seems to say that it cannot compare two std::reference_wrapper<const Object> objects, but it seems that it should be possible - std::reference_wrapper has a conversion operator that can implicitly convert it to T& ( const Object & here), and Object has an operator < , so why doesn't it work?

Should it work and is this just a bug in g ++? Or is something else going on?

+6
source share
3 answers

This seems to work if you make the comparison operator a free function (which possibly calls a virtual member function).

If it is a member function, a < b really means a.operator<(b); , and implicit conversions are not considered for the left side argument.

+5
source

By default, std::less<std::reference_wrapper<const Object>> , but it does not forward operator<() to the base type.

The simplest and most concise option for solving your problem is to define std::less<const Object> (or std::greater<const Object> ) in the map definition as follows:

 std::map<std::reference_wrapper<const Object>, int, std::less<const Object>> table; 

It will work correctly and, as expected, from the implicit conversion of std::reference_wrapper to T& and the implicit constructor std::reference_wrapper .

An example .

+3
source

In Visual Studio 11 Beta, I have the same problem. Using the free version that calls the <operator solves the problem.

 #include<map> #include<iostream> using namespace::std; class Object { int _n1; public: Object(int n = 0):_n1(n){}; bool operator < (const Object& rhs) const {return this->_n1 < rhs._n1;} friend ostream &operator << (ostream &stream, const Object& o) { stream << o._n1 << " "; return stream;} }; struct ObjectLess{ bool operator()(const Object& lhs, const Object& rhs) const { return lhs<rhs; } }; int main(int argc, char* argv[]) { //This does not compile //std::map<std::reference_wrapper<const Object>, string> table; //Using the free function works std::map<std::reference_wrapper<const Object>, string, ObjectLess> table; Object a(1); Object b(2); Object c(3); table[a]="One"; table[c]="Three"; table[b]="Two"; for(auto y: table){ cout << y.first << " " << y.second.c_str() << std::endl; } return 0; } 
+1
source

All Articles