2

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

4

1 回答 1

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是 typestd::reference_wrapper<T>时,该对中的类型将被 decuced 为T&。这实际上为您提供了正确的解决方案:obj在调用中std::cref包含:make_pair

myMap.emplace(std::make_pair(std::cref(obj), value));

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

于 2017-08-16T14:06:46.733 回答