从引用到std :: reference_wrapper或编译器错误的隐式转换的错误理解?

时间:2017-08-16 13:56:51

标签: c++ reference implicit-conversion reference-wrapper

我对涉及引用和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中的已知问题/缺陷无法正确扣除传递给它的类型吗?

1 个答案:

答案 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),这正是您想要的。