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

A. *_*lma 2 c++ reference implicit-conversion reference-wrapper

我对涉及引用和std :: reference_wrapper的一些代码感到困惑,我不清楚这是否是我的错,因为我误解了引用包装器的工作原理或者我遇到编译器错误.

我有一个简单的映射,将对象的引用与复杂类配对:

std::unordered_map<Object const &obj, int32_t value> myMap;
Run Code Online (Sandbox Code Playgroud)

(为简单起见,我明确地省略了地图编译所需的哈希和相等的仿函数)

由于我不能直接在地图中使用引用,我使用它的引用包装:

std::unordered_map<std::reference_wrapper<const Object> obj, int32_t value> myMap;
Run Code Online (Sandbox Code Playgroud)

现在,我的地图填充在以下功能中:

void myFunction(Object const &obj, int32_t value)
{
    ...
    myMap.emplace(std::make_pair(obj, value));
}
Run Code Online (Sandbox Code Playgroud)

但该代码虽然编译,但不起作用.但是,这个按预期工作:

void myFunction(Object const &obj, int32_t value)
{
    ...
    myMap.emplace(std::pair<std::reference_wrapper<const Object>, int32_t>(obj, value));
}
Run Code Online (Sandbox Code Playgroud)

(在第二个版本中注意我还没有明确地为obj构建一个引用包装器)

所以,我的怀疑是:

我是否误解了参考包装器的用法?从引用到reference_wrapper没有隐式转换?如果没有,为什么代码首先编译?

或者这是std :: make_pair中的已知问题/缺陷无法正确扣除传递给它的类型?

Rei*_*ica 5

std::make_pairnever (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));
Run Code Online (Sandbox Code Playgroud)

这将导致临时对包含引用,并且reference_wrapper映射内部将绑定到其引用的对象(obj),这正是您想要的.