问题标签 [reference-wrapper]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
1298 浏览

c++ - 为什么 `std::reference_wrapper`s 中不能推导出模板实例?

假设我有一些 type 的对象T,我想把它放到一个引用包装器中:

现在我可以很容易地说if (p < q),因为引用包装器已经转换为它的包装类型。一切都很开心,我可以处理一组引用包装器,就像它们是原始对象一样。

(正如下面链接的问题所示,这可能是生成现有集合的替代视图的有用方法,可以随意重新排列而不产生完整副本的成本,以及保持与原始集合的更新完整性。 )


但是,对于某些类,这不起作用:

我的解决方法是定义一个谓词,如this answer *; 但我的问题是:

为什么以及何时可以将运算符应用于引用包装器并透明地使用包装类型的运算符?为什么会失败std::string?它与std::string模板实例有什么关系?

*)更新:根据答案,似乎 usingstd::less<T>()是一个通用的解决方案。

0 投票
1 回答
2991 浏览

c++ - std::reference_wrapper 是否应该包含默认比较器“<”运算符?

STL 使用“小于”作为默认比较器。即使基础类定义了“<”运算符,对使用 reference_wrapper<> 包装的对象的 STL 比较器调用也不会编译。

看来,这是因为当LHS.operator<(RHS)是成员函数时,没有在LHS上执行隐式转换。我已经验证了使用免费版本作为比较器的工作原理。

但是,如果 reference_wrapper 提供了“<”运算符,它在底层调用“<”,则无需使用 free 函数。

我在 reference_wrapper 的代码中添加了以下内容(取自 VS11 Beta xrefwrap.h),并且可以将 std::map 与包装在我的 reference_wrapper<> 版本中的类一起使用,该版本定义了“<”运算符。

稍后添加:如果我理解正确,reference_wrapper<> 提供了与许多库所需的 ptr 相关的复制/分配语义,同时隐藏了与 ptr 相关的语法。这允许使用引用类型语法,而没有本地副本的开销。将它与使用 ptrs 的示例进行比较完全错过了 reference_wrappers 的要点之一:要避免使用 ptr 类型语法。

现在的情况是,直接作用于对象的代码在对象被包装在 reference_wrappers 中时会中断。不用说,“<”是默认的比较器,确实使它特别;在现有代码的很大一部分中,对象将定义这些以消除对特殊比较器的需要。

稍后添加 #2:此功能的历史表明,避免使用 ptr 语法并不是最初的意图。然而,自从它首次在 boost 中引入以来已经有十年了。随着大量新程序员“指导”避免使用基于 ptr 的语法(无疑受到 ptr 自由语言的影响),如果它可以更无缝地工作,特别是在处理在 STL 容器中存储对象的遗留代码时,此功能将变得越来越有用,并且价值复制遍地。

稍后添加 #3:以最少的代码更改改进遗留代码 随着时间的推移,瘦类变得繁重,容器中对象的大小增加。提高性能的一种快速方法是通过包装对象避免复制。这将提供“C ptr”类型的性能,而无需对代码进行最小更改的额外副本。

0 投票
2 回答
281 浏览

c++ - 有什么类似于 std::value_wrapper 与 std::reference_wrapper 平行的东西吗?

更新:这个问题源于一个包装类的实现,该包装类通过值传递一个对象,该对象对const Fooand具有不同的含义Foo,这一举动完全基于这里人们的强烈意见。之前,我一直在传递const Foo*Foo*当包装器来了,我把它换成了Wrapper<Foo>and const Wrapper<Foo>现在很明显,机械替换没有意义,我需要更复杂的东西,比如Wrapper<Foo>and Wrapper<const Foo>...虽然我不知道如何正确地写还没有。对造成的误解表示歉意,但我会在这里保留这个,因为我实际上认为它比许多问题更能说明问题。


在调查这个问题时,它似乎归结为与你不能这样做的想法平行:

就像引用一样,一个 const 值不能被重新定位。执行以下操作会编译,但不是我(在这种情况下)想要的:

似乎(根据我的理解)reference_wrapper可以在参考案例中解决这个问题,例如:

我想知道是否有一个“ value_wrapper”在那里做类似的事情。出于 const 正确性的原因,想要一个按值保存项目的变量对我来说似乎是合理的……而不是因为您不打算更改它。 (例如在前序树遍历中跟踪当前节点,尽管只有 const 访问该树中的节点,其中将前一个节点传递给函数是获取新节点的方式)

如果你想变得笨重,你可以使用std::pair<const Foo, bool>并忽略bool

但是,除了实现我自己的“”版本之外,还有更好的方法来解决这个问题value_wrapper吗?

0 投票
2 回答
543 浏览

c++ - 如何避免 std::reference_wrapper 衰减为 std::make_tuple 中的普通引用?

我正在尝试正确地std::reference_wrapper为对象生成一个 s 元组。通过使用此处显示的技术,我设法将std::ref函数映射到所有原始元组,但是,根据这一点(并且它实际上发生了),在此过程中会衰减std::reference_wrapper为普通的refs (&)。有没有办法避免这种情况?我有一整套接受s 元组的函数,我不想将它们更改为使用引用。std::reference_wrapper

谢谢

0 投票
2 回答
1399 浏览

c++ - C++ std::reference_wrapper 如何隐式转换为引用?

我最近开始使用这个std::reference_wrapper类。在替换原始引用的某些用途时,我注意到我不必使用该get()函数将 reference_wrappers 作为参数传递给采用普通引用的函数。

std::reference_wrapper传递给函数时如何隐式转换为原始引用?

0 投票
1 回答
318 浏览

c++ - std::reference_wrapper 何时转换为 T&?

考虑以下代码:

此代码打印“8”。我假设 fun() 中的 t 会自动转换为 int&。

但是如果我用 替换t+=8t=8程序将无法编译。

为什么?

0 投票
3 回答
1441 浏览

c++ - 为什么 std::make_tuple 变成 std​​::reference_wrapperX&? 的参数

在 C++11 标准中,它声明(参见cppreference.com,另请参见标准的第 20.4.2.4 节)它声明

创建一个元组对象,从参数类型推导出目标类型。

对于每个Tiin Types...,对应的类型ViinVtypes...std::decay<Ti>::type,除非应用std::decay结果 instd::reference_wrapper<X>某些类型X,在这种情况下,推导的类型是X&

我想知道:为什么参考包装在这里被特殊对待?

0 投票
1 回答
2137 浏览

c++ - 访问向量 c++11 中的引用包装器元素

在图表类中:

在另一个使用图的类中:

现在我正在尝试通过执行访问优先级队列(PECMP someQueue)中的第一个元素

但是我收到以下错误:

访问存储在引用包装器中的元素的更好方法是什么?谢谢

0 投票
0 回答
323 浏览

c++ - 包装对象的语义:默认情况下通过 std::move/std::ref 引用/值

最近,我经常使用我在 C++11 中“发现”的一个自然习语,即包装对象可以在可能的情况下自动保持引用。这里的主要问题是将这个“成语”的行为与标准中的其他行为进行比较(见下文)。

例如:

以这种方式为代码

我明白了,

如果我小心(使用悬空引用),我可以处理得很好。如果我想避免引用,我会这样做:

因此,这种行为在 C++11 中似乎很自然。

然后我又回去了std::pairstd::make_pair不知何故,我希望他们使用这种新的看似自然的行为,但显然这种行为是“更传统的”。例如:

和参考

这记录在这里:http ://en.cppreference.com/w/cpp/utility/pair/make_pair

如您所见,这两种行为是“相反的”,在某种意义上std::ref是对std::move. 所以这两种行为最终都同样灵活,但在我看来,这种std::make_pair行为更难实现和维护。

问题是:当前std::make_pair默认丢弃引用的行为是否只是向后兼容性问题?因为一些历史预期?还是 C++11 中仍然存在更深层次的原因?

事实上,这种行为看起来std::make_pair更难实现,因为它需要对std::ref( std::reference_wrapper)进行专门std::decay化,甚至看起来不自然(在“C++11 move”的情况下)。同时,即使我决定继续使用第一种行为,我也担心这种行为相对于当前标准来说是非常出乎意料的,即使在 C++11 中也是如此。

事实上,我非常喜欢第一种行为,以至于优雅的解决方案可能会更改前缀make_somethingconstruct_something标记行为差异。(编辑:建议查看的评论之一std::forward_as_tuple,因此可能是另一个名称约定forward_as_something)。关于命名,在对象的构造中混入pass-by-ref、pass-by-ref时的情况并不明确。


EDIT2:这是一个编辑,只是为了回答@Yakk 关于能够“复制”具有不同参考/值属性的包装对象。这不是问题的一部分,它只是实验代码:

这似乎允许我在不相关的类型wrap<T&>和之间进行复制wrap<T>


EDIT3:此编辑是添加一个具体示例,在该示例中,传统的参考扣除可能会失败,这取决于“协议”。该示例基于 Boost.Fusion 的使用。

我发现从引用到值的隐式转换在多大程度上取决于约定。例如,好的旧 Boost.Fusion 遵循 STL 约定

Fusion 的生成函数(例如 make_list)默认将元素类型存储为普通的非引用类型。

然而,这依赖于标记引用的确切“类型”,在 Fusion的情况下是,在is...boost::ref的情况下,是一个完全不相关的类。所以,目前,给定make_pairstd::ref

的类型boost::fusion::make_vector(5., a )boost::fusion::vector2<double, double>。好的。

以及boost::fusion::make_vector(5., boost::ref(a) ) ) isboost::fusion::vector2` 的类型。好的,如文件所述。

然而,令人惊讶的是,由于 Boost.Fusion 不是用 C++11 STL 编写的,我们得到: boost::fusion::make_vector(5., std::ref(a) ) )is of type boost::fusion::vector2<double, std::reference_wrapper<double const> >. 惊喜!

本节旨在说明当前的 STL 行为依赖于协议(例如,使用什么类来标记引用),而另一个(我称之为“自然”行为)使用std::move(或更准确地说是右值转换)不依赖于协议一个协议,但它更原生于(当前)语言。

0 投票
3 回答
442 浏览

c++ - 通过矢量> 到矢量?

我有一个很大的std::vector<int> a,但我只想处理它的一个子集。这个想法是创建一个std::vector<reference_wrapper<int> > refa只包含上述子集的(在 mwe 中,所有元素 1 a<<4)。然后我想传递refa给期望 astd::vector<int>std::vector<int>&作为参数的函数(因为我也想将它们与 一起使用a)。a可能会很大,我想避免多次选择。

问题

如何正确传递refa给函数?我想要的是bar(refa)foobar(refa)工作。

有没有更好的方法来解决问题,而不改变功能(太多)?

代码

注意 int在这里仅用于保持示例简单。