对从引用到 std::reference_wrapper 或编译器错误的隐式转换的理解不正确?
Incorrect understanding of implicit conversion from reference to std::reference_wrapper or compiler bug?
我对一些涉及引用和 std::reference_wrapper 的代码感到困惑,而且我完全不清楚这是否是我的错,因为我误解了引用包装器的工作方式,或者我遇到了编译器错误。
我有一个简单的映射,将一个对象的引用从一个复杂的 class 配对到一个值:
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 中的已知 issue/flaw 无法正确扣除传递给它的类型?
std::make_pair
从不 (1) 将引用类型推导为对中的一种类型,它总是产生值类型。所以对 emplace
的调用接收一个 temporary std::pair<Object, int32_t>
作为参数。然后从这个临时文件初始化引用包装器,这意味着它将绑定到这个 temporary 对的 first
成员。
在第二种情况下,临时文件的类型为 std::pair<std::reference_wrapper<const Object>, int32_t>
(因为您已明确要求),这意味着临时文件对中有一个引用包装器,直接绑定到 obj
.然后从这个临时引用包装器复制映射内的引用包装器,因此直接引用 obj
.
(1) "Never" 在这里不是真的。有一个例外:当 std::make_pair
的参数之一是 std::reference_wrapper<T>
类型时,该对中的类型将被减为 T&
。这实际上为您提供了正确的解决方案:在 make_pair
调用中将 obj
包装在 std::cref
中:
myMap.emplace(std::make_pair(std::cref(obj), value));
这将导致临时对包含引用,并且映射中的 reference_wrapper
将绑定到其引用的对象 (obj
),这正是您想要的。
我对一些涉及引用和 std::reference_wrapper 的代码感到困惑,而且我完全不清楚这是否是我的错,因为我误解了引用包装器的工作方式,或者我遇到了编译器错误。
我有一个简单的映射,将一个对象的引用从一个复杂的 class 配对到一个值:
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 中的已知 issue/flaw 无法正确扣除传递给它的类型?
std::make_pair
从不 (1) 将引用类型推导为对中的一种类型,它总是产生值类型。所以对 emplace
的调用接收一个 temporary std::pair<Object, int32_t>
作为参数。然后从这个临时文件初始化引用包装器,这意味着它将绑定到这个 temporary 对的 first
成员。
在第二种情况下,临时文件的类型为 std::pair<std::reference_wrapper<const Object>, int32_t>
(因为您已明确要求),这意味着临时文件对中有一个引用包装器,直接绑定到 obj
.然后从这个临时引用包装器复制映射内的引用包装器,因此直接引用 obj
.
(1) "Never" 在这里不是真的。有一个例外:当 std::make_pair
的参数之一是 std::reference_wrapper<T>
类型时,该对中的类型将被减为 T&
。这实际上为您提供了正确的解决方案:在 make_pair
调用中将 obj
包装在 std::cref
中:
myMap.emplace(std::make_pair(std::cref(obj), value));
这将导致临时对包含引用,并且映射中的 reference_wrapper
将绑定到其引用的对象 (obj
),这正是您想要的。