我对涉及引用和std :: reference_wrapper的一些代码感到困惑,而且我不清楚这是否是我的错,因为我误解了引用包装器的工作方式或是否编译错误。
我有一个简单的地图,将对象的引用与复杂类配对:
std::unordered_map<Object const &obj, int32_t value> myMap;
(为简单起见,我明确地省略了地图编译所需的哈希和相等的仿函数)
由于我无法在地图中直接使用引用,因此我使用了引用包装器:
std::unordered_map<std::reference_wrapper<const Object> obj, int32_t value> myMap;
现在,我的地图填充在以下函数中:
void myFunction(Object const &obj, int32_t value)
{
...
myMap.emplace(std::make_pair(obj, value));
}
但该代码虽然编译,却无法正常工作。但是,这个按预期工作:
void myFunction(Object const &obj, int32_t value)
{
...
myMap.emplace(std::pair<std::reference_wrapper<const Object>, int32_t>(obj, value));
}
(在第二个版本中注意我还没有明确地为obj构建一个引用包装器)
所以,我怀疑是:
我是否误解了参考包装器的用法?从引用到reference_wrapper没有隐式转换?如果没有,为什么代码首先编译?
或者这是std :: make_pair中的已知问题/缺陷无法正确扣除传递给它的类型吗?
答案 0 :(得分:5)
std::make_pair
从不(1)将引用类型推导为该对中的一个类型,它总是生成值类型。因此,对emplace
的调用会收到临时 std::pair<Object, int32_t>
作为参数。然后从该临时值初始化引用包装器,这意味着它将绑定到此临时对的first
成员。
在第二种情况下,临时类型为std::pair<std::reference_wrapper<const Object>, int32_t>
(因为您已明确请求),这意味着临时对中有一个引用包装器,直接绑定到obj
。然后,从该临时引用包装器复制映射中的引用包装器,从而直接引用obj
。
(1)“从不”这里不正确。有一个例外:当std::make_pair
的其中一个参数属于std::reference_wrapper<T>
类型时,该对中的类型将被解除为T&
。这实际上为您提供了正确的解决方案:在obj
调用中的std::cref
中包裹make_pair
:
myMap.emplace(std::make_pair(std::cref(obj), value));
这将导致临时对包含引用,并且映射中的reference_wrapper
将绑定到其引用的对象(obj
),这正是您想要的。