简体   繁体   English

使用 std::reference_wrapper 作为 std::map 中的键

[英]Using std::reference_wrapper as the key in a std::map

I have a bunch of objects in a class hierarchy and would like to make a std::map using references to those objects as the keys in the map.我在 class 层次结构中有一堆对象,并且想使用对这些对象的引用作为 map 中的键来制作std::map map。 Its seems like std::reference_wrapper would be exactly what is needed for this, but I can't seem to make it work.似乎std::reference_wrapper正是为此所需要的,但我似乎无法使其工作。 What I've 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 somewhat obscure 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 be saying it can't compare two std::reference_wrapper<const Object> objects, but it seems like it should be possible -- std::reference_wrapper has a conversion operator that can implicitly convert it to a T& ( const Object & here), and Object has a operator < , so why doesn't it work?该错误似乎是说它无法比较两个std::reference_wrapper<const Object>对象,但似乎应该是可能的—— std::reference_wrapper有一个转换运算符可以将其隐式转换为T&const Object &这里),和Object有一个operator < ,为什么它不起作用?

Should it work and this is merely a bug in g++?它应该工作吗?这仅仅是 g++ 中的一个错误? Or is something else going on?还是发生了其他事情?

It seems that it would work if you made the comparison operator a free function (that perhaps calls a virtual member function). 如果你将比较运算符设置为自由函数(可能调用虚拟成员函数),它似乎会起作用。

If it is a member function, a < b really means a.operator<(b); 如果它是一个成员函数, a < b实际上意味着a.operator<(b); and implicit conversions are not considered for the left-side argument. 左侧参数不考虑隐式转换。

By default std::map uses std::less<std::reference_wrapper<const Object>> as Compare , but std::reference_wrapper<T> doesn't forward operator<() to the underlying type T . 默认情况下, std::map使用std::less<std::reference_wrapper<const Object>>作为Compare ,但是std::reference_wrapper<T>不会将operator<()转发给基础类型T

The simplest and concisest option to solve your problem is to define std::less<const Object> (or std::greater<const Object> ) in the map definition like this: 解决问题的最简单和最简单的选择是在地图定义中定义std::less<const Object> (或std::greater<const Object> ),如下所示:

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

It will work correctly and as expected due to implicit conversion of std::reference_wrapper to T& and implicit constructor of std::reference_wrapper . 由于std::reference_wrapper隐式转换为T&std::reference_wrapper隐式构造函数,它将正常工作并且符合预期。

Example . 例子

On Visual Studio 11 Beta, I get the same problem. 在Visual Studio 11 Beta上,我遇到了同样的问题。 Using the free version which 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM