我看了 Scott Meyers 关于通用引用的视频,他告诉我,任何时候使用通用引用时,都必须像这样转发它:
template<typename T>
auto func(T &&a) { return ++std::forward<T>(a); }
然后推论this
我们得到:
auto member_func(this auto &&self) { return self.member_variable; }
这里在哪儿std::forward<???>(self).member_variable
?我错过了什么?
通常,显式对象参数中的转发引用应该像任何其他转发引用一样进行转发:
总体来说,这里与其他转发参考没有什么不同。你没有说明代码来自哪里,所以我无法判断作者为什么决定不转发,或者这是否是这个特定情况下的问题。
但是,由于这是成员函数的显式对象参数,因此您通常可以假设其类型
self
,这与一般函数模板中的大多数转发引用相反。它将是其所在的类的类型或派生类类型。在这种情况下,可以合理地假设它将
member_variable
引用在同一个类中声明的成员member_variable
。并且您知道该成员的类型。现在假设它看起来像这样:
self.member_variable
那么可以合理地假设的类型为int
,并且对于 来说,无论是从左值还是右值表达式int
按值返回 ( ) 都没有任何区别。调用将被认为没有效果。auto
std::forward
存在的问题:
成员函数不受其自身出现的类类型的限制。如果类类型未标记
final
或成员函数声明为private
,则可能会在派生类类型上调用它,该派生类类型还定义了member_variable
不同类型的。这将被发现return self.member_variable;
并且它可能具有转发可能会产生影响的类型,例如std::string
。但是,我不清楚代码作者是否考虑过这种情况,或者他们是否真的想始终返回
member_variable
类本身。如果self.A::member_variable
是那样的话,应该是这样的。在这种情况下,多重继承和私有继承仍然存在问题。(不过私有继承有一个解决方案。)如果转发引用未被转发,那么在这种情况下根本没有必要使用显式对象参数
this auto&&
。它可以简单地声明为this const auto&
或this const A&
,这也可以避免上述问题。事实上,它可以只是一个没有显式对象参数的普通非静态成员函数。由于可以形成指向显式成员函数的函数指针,因此可以通过任何其他类型的指针间接调用成员函数
self
。同样,可以通过显式指定类型的模板参数来强制隐式转换为任何类型的类型。auto
但是,这些不是正常用例,函数可能不需要考虑它们。此外,通常情况下,记住使用的
std::forward
含义也很重要。简单地将std::forward
任何作为转发引用的变量应用于该变量都是错误的。这std::forward
会导致作为操作数的表达式(可能)消耗对象的状态。它通常只能在函数体中应用一次,之后就不应该再使用该对象了。如果成员访问表达式如下
有点不同:这里
std::forward
只会导致会员的潜在消费member_variable
。其余会员仍保证保持其之前的状态。因此可以std::forward
为每个会员单独申请一次。