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

10

我有一堆类层次结构中的对象,想要使用这些对象的引用作为std::map中的键。看起来std::reference_wrapper应该是正好需要的东西,但我似乎无法让它正常工作。 我已经尝试过的:

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]++

然而,我总是从编译器得到一些比较晦涩的错误:

/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 foroperator<’ in ‘__x < __y’

出错似乎在于无法比较两个std::reference_wrapper<const Object>对象,但是它应该是可以比较的 — std::reference_wrapper具有一个转换运算符,可以将其隐式转换为T&(这里是const Object &),而Object具有operator <,那么为什么不起作用呢?

它应该可以正常工作,这只是g++的一个bug吗?还是其他的问题发生了?


std::ref(object) < std::ref(object) 能编译通过吗? - dalle
3个回答

15
默认情况下,std::map 使用 std::less<std::reference_wrapper<const Object>> 作为 Compare,但是 std::reference_wrapper<T> 不会将 operator<() 转发给底层类型 T
解决问题的最简单和最简洁的选项是在地图定义中定义 std::less<const Object>(或 std::greater<const Object>)。
std::map<std::reference_wrapper<const Object>, int, std::less<const Object>> table;

由于std::reference_wrapper隐式转换为T&std::reference_wrapper的隐式构造函数, 它将正确地工作并按预期运行。

示例


8
似乎如果将比较运算符作为自由函数(可能调用虚拟成员函数),它就能够工作。
如果是成员函数,a < b 实际上意味着 a.operator<(b);,左侧参数不会考虑隐式转换。

如果可能的话,非成员operator的另一个优点是什么呢?现在我开始更多地使用reference_wrapper,可能需要重新进行一些重构。 - underscore_d

1
在Visual Studio 11 Beta上,我遇到了同样的问题。 使用调用<运算符的免费版本可以解决这个问题。
#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;
}

我从粗略的看法中没有理解struct Objectless的目的,所以我继续尝试构建它,以便玩一下代码。好吧,它无法编译,我得到了/usr/include/c++/8.1.1/bits/stl_tree.h:452:21: error: static assertion failed: comparison object must be invocable with two arguments of key type static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{} - Hi-Angel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接