问题标签 [perfect-forwarding]

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 投票
3 回答
1058 浏览

c++ - 何时不将 std::forward 与 r 值一起使用?

什么情况下 std::forward不需要?它用于包装内部函数参数,即模板右值(即,它可以是左值或命名右值)。像:

我猜一种情况是内部函数参数按值传递。还有其他情况吗?我在写std::begin(std::forward<Ct>(ct))Ct 是模板右值引用的地方时遇到了这个问题。

编辑关于可能的重复

如果我没记错的话,这是第三次尝试关闭这个 4 年的老问题,因为一些不懂这个问题的新手重复了这个问题。

“使用前锋的好处?” 和“什么时候不使用带有 r 值的 std::forward?” 是非常不同的问题。首先是为初学者介绍 r 值,其次是为高级 C++ 用户讨论完美转发。我是元模板库和 lambda 库的作者,他们不需要对基础知识进行详细描述。答案中的信息与其他问题非常不同。

0 投票
1 回答
665 浏览

c++ - 检测(可能是抽象的)基类的受保护构造函数

我正在试验 C++11 的新特性。在我的设置中,我真的很想使用继承构造函数,但不幸的是还没有编译器实现这些。因此,我试图模拟相同的行为。我可以这样写:

这工作......大部分时间。有时使用Wrapper类的代码必须使用 SFINAE 来检测如何Wrapper<T>构造这样的类。然而,存在以下问题:就重载决议而言,构造函数将接受任何参数——但如果无法使用这些参数构造类型Wrapper<T>,则编译将失败( SFINAE涵盖这一点) 。T

我试图使用有条件地启用构造函数模板的不同实例化enable_if

只要:

  • Tis的适当构造函数public
  • T不是抽象的

我的问题是:如何摆脱上述两个约束?

我试图通过检查(使用 SFINAE 和sizeof())来克服第一个表达式new T(std::declval<As &&>()...)是否 Wrapper<T>. 但这当然行不通,因为派生类可以使用其基类的受保护构造函数的唯一方法是在成员初始化列表中。

对于第二个,我完全不知道——它是我更需要的一个,因为有时它Wrapper实现了 的抽象函数T,使其成为一个完整的类型。

我想要一个解决方案:

  • 根据标准是正确的
  • 适用于任何 gcc-4.6.*、gcc-4.7.* 或 clang-3.*

谢谢!

0 投票
3 回答
188 浏览

c++ - R值和L值的输出不同。为什么?

有人可以向我解释为什么 R 值的输出与 L 值不同吗?

输出(gcc48 和 clang32 相同):

回答

它在我与 Johannes Schaub 的聊天中被埋没了,所以我把它放在这里。

当临时向量初始化 r-value-ref member-variablerv.ct时,临时生命周期不会延长,因为有一个特殊的例外:[class.temporary]p5:“在构造函数的 ctor-initializer (12.6.2) 中临时绑定到引用成员一直持续到构造函数退出。”

0 投票
3 回答
6741 浏览

c++ - 返回值的转发。需要 std::forward 吗?

我正在编写包含其他库中的许多函数和方法的库。为了避免处理返回值,我这样应用std::forward

f返回void和接受T&&(或重载价值)。包装器始终返回包装器的参数,并且返回值应保留参数的价值。我真的需要使用std::forwardinreturn吗?RVO 是否让它变得多余?它是参考(R 或 L)这一事实是否使它变得多余?如果 return 不是最后一个函数语句(在某些 if 中),是否需要它?

是否wrapper()应该返回voidor是有争议的T&&,因为调用者可以通过 arg 访问评估值(即引用,R 或 L)。但在我的情况下,我需要返回值,以便wrapper()可以在表达式中使用。

这可能与问题无关,但众所周知,函数f不会从 中窃取t,因此第一次使用std::forwardinf(std::forward<T>(t))是多余的,它被我删除了。

我写过小测试:https ://gist.github.com/3910503

测试表明,返回未转发的T- 确实会在 gcc48 和 clang32 中使用 -O3 创建额外的副本(RVO 不会启动)。

此外,我无法从 UB 获得不良行为:

它不能证明任何原因,因为它是未定义的行为(如果它是 UB)。

0 投票
3 回答
1658 浏览

c++ - 类层次结构中完美转发构造函数和复制构造函数之间的冲突

我最近在尝试使用完美的转发构造函数实现类层次结构时遇到了一个问题。考虑以下示例:

当我尝试编译代码时,出现以下错误:

错误 3 错误 C2664: 'std::basic_string<_Elem,_Traits,_Alloc>::basic_string(const std::basic_string<_Elem,_Traits,_Alloc> &)' : 无法将参数 1 从 'const Test' 转换为 'const std ::basic_string<_Elem,_Traits,_Alloc> &'

我的理解是编译器将完美的转发构造函数视为比复制构造函数更好的数学。参见例如Scott Meyers: Copying Constructors in C++11。在其他没有类层次结构的实现中,我可以通过 SFINAE 禁用完美转发构造函数作为复制构造函数。例如,参见Martinho Fernandes:转发构造函数的一些陷阱。当我尝试将上述解决方案应用于此示例时,我仍然无法使用相同的错误消息进行编译。

我认为一种可能的解决方案是避免完美转发,在构造函数中按值获取参数,而不是从它们移动到类变量。

所以我的问题是这个问题是否有其他解决方案,或者在这种情况下是否不可能完美转发?

更新: 原来我的问题很容易被误解。所以我会试着澄清一下我的意图和背景。

  • 代码是完整的,就像问题中发布的一样。没有创建其他对象或调用函数。尝试编译发布的示例时出现错误。
  • 拥有完美的转发构造函数的目的是用于成员初始化,而不是拥有某种额外的复制构造函数。这里的原因是在使用临时对象初始化成员时保存一些对象副本(正如 Scott Meyers 在会谈中提出的那样)
  • 不幸的是,事实证明,完美的转发构造函数可能与其他重载的构造函数发生冲突(在此示例中为复制构造函数)。
  • 就像建议的这个问题的答案和评论一样:这里可能的解决方案是引入显式强制转换或具有单独的非模板构造函数(即,关于具有两个分别带有参数const string&和的构造函数的示例string&&)。
0 投票
2 回答
7832 浏览

c++ - 我可以通常/总是使用 std::forward 而不是 std::move 吗?

我一直在观看 Scott Meyers在 C++ 和 Beyond 2012 会议上关于通用引用的演讲,到目前为止一切都很有意义。然而,一位观众在大约 50 分钟时提出了一个我也想知道的问题。迈耶斯说他不关心答案,因为它是非惯用的并且会让他的头脑变得愚蠢,但我仍然感兴趣。

呈现的代码如下:

关键是当我们采用右值引用时,我们知道我们有一个右值,所以我们应该std::move保留它是一个右值的事实。当我们采用通用引用(T&&,其中T是推导类型)时,我们希望std::forward保留它可能是左值或右值的事实。

所以问题是:既然std::forward保留了传递给函数的值是左值还是右值,并且std::move只是将其参数转换为右值,我们可以std::forward在任何地方使用吗?在我们使用 的所有情况下都会std::forward表现得像,还是迈耶斯的概括遗漏了一些重要的行为差异?std::movestd::move

我并不是建议任何人都应该这样做,因为正如 Meyers 正确所说,它完全不是惯用的,但以下也是 的有效用法std::move

0 投票
1 回答
114 浏览

c++ - 本例中 move 和 forward 的区别

第一个按值取 A 的例子做了两步,而通过 refref 的例子只做了一次。有什么不同?

0 投票
1 回答
79 浏览

c++ - 转发复制构造函数的问题

任何人都知道为什么转发复制ctor不起作用?

关于一种类型是向量而另一种类型是堆栈的编译器错误???

0 投票
1 回答
3599 浏览

c++ - 在 C++ 中重命名(别名/转发)函数的最佳方法是什么?

(我将把这个问题限制在 C++11,因为我相信在 C++98 中没有通用的方法来做到这一点)。

假设我有一组复杂的(就签名而言)模板函数和/或重载函数,并且我想以完全相同的方式使用这些函数,但使用不同的名称(即别名)。

例如:

现在假设我想一次重命名(或alias,或更准确地说是forward)这些函数(即能够为同一个函数使用不同的名称而无需重写它)。这样,在代码的其他部分,我可以用不同的名称使用它,而无需修改上述代码。

这是将(别名/转发)重命名fun为的正确方法gun吗?

  • 真的一般吗?
  • 这是最简单的方法吗?
  • 这是最佳方式吗?(例如可以内联,没有不必要的副本)
  • 如果原始函数有一些 SFINAE 特性怎么办?(例如template<class A, class B, class C, class = std::enable_if< ... >::type>),是否会decltype在所有情况下转移 SFINAE?
  • 如果原始函数返回引用怎么办?decltype 不会删除引用类型吗?(例如double& fun(double& x){return x;})。
  • 成员函数也可以这样说吗?

澄清:gun永远不会完全正确 fun,因为实例将具有不同的地址,但我正在寻找的是从通用编码的角度重命名。

评论:我觉得奇怪的是,几乎所有东西都可以重命名/转发,命名空间、类型 ( typedef) 和模板类型using typedef,但不是函数(或就此而言的成员函数)。


编辑:为了完整起见,因为这似乎是这样做的方法,所以我在这里添加了一个宏来定义函数别名:

然后你像这样使用它:


EDIT2:我认为异常策略也可以合并到别名中:

但还没有测试它。 您必须键入三遍

0 投票
1 回答
9123 浏览

c++ - 完美转发到异步 lambda

我有一个函数模板,我想在其中完美地转发到我在另一个线程上运行的 lambda。这是一个可以直接编译的最小测试用例:

对于非编译情况,这是错误消息的最后一行,这是可以理解的:

我有一种感觉,它可能与如何T&&推断有关,但我无法确定确切的故障点并修复它。有什么建议么?

谢谢!

编辑:我正在使用 gcc 4.7.0 以防万一这可能是编译器问题(可能不是)