通用引用:为什么推导这个没有std::forward?

问题描述 投票:0回答:1

我观看了 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
在哪里?我错过了什么?

c++ perfect-forwarding c++26
1个回答
0
投票

通常,显式对象参数中的转发引用应该像任何其他转发引用一样转发:

auto member_func(this auto &&self) {
    return std::forward<decltype(self)>(self).member_variable;
}

总的来说,这里与其他转发参考没有什么不同。您没有说明您从哪里获得代码,所以我无法判断为什么作者决定不转发或者这是否是这个特定实例中的问题。

但是,因为这是一个成员函数,所以您通常可以假设

self
将具有什么类型,这与一般函数模板中的大多数转发引用相反。它将是编写它的类的类型或派生类类型。

在这种情况下,可以合理地假设

member_variable
将引用在同一类中声明的成员
member_variable
。而且您知道该成员属于什么类型。

现在假设它看起来像这样:

struct A {
    int member_variable;
    auto member_func(this auto &&self) { return self.member_variable; }
};

那么

self.member_variable
的类型可以合理地假设为
int
,并且对于
int
来说,无论它是从左值还是右值表达式按值 (
auto
) 返回,都完全没有区别。
std::forward
调用将不会产生任何效果。

问题:

  1. 成员函数不限于它本身出现的类类型。如果类类型未标记为

    final
    或未声明成员函数
    private
    ,则可能会在还定义了不同类型的
    member_variable
    的派生类类型上调用它。这将在
    return self.member_variable;
    中找到,并且它可能具有转发可以产生影响的类型,例如
    std::string

    但是,对我来说,代码的作者是否考虑了这种情况,或者他们是否真的想要always返回类本身的

    member_variable
    并不明显。在这种情况下,它应该是
    self.A::member_variable
    或类似的东西。在这种情况下,多重继承仍然存在问题。

  2. 如果转发引用没有被转发,那么在这种情况下,显式对象参数是

    this auto&&
    根本没有意义。可以简单地声明为
    this const auto&
    this const A&
    ,这也可以避免上述问题。

  3. 因为可以形成指向显式成员函数的函数指针,所以可以通过这样的任何其他类型的指针来间接调用成员函数

    self
    。同样,可以通过显式指定
    auto
    类型的模板参数来强制隐式转换为任何类型。然而,这些不是正常的用例,函数可能不需要考虑它们。

© www.soinside.com 2019 - 2024. All rights reserved.