转发引用、引用限定符和模板成员函数

Forwarding references, ref qualifiers and template member functions

本文关键字:引用 函数 成员 转发      更新时间:2023-10-16

取以下成员函数:

struct T {
    template <typename X> void f(X&& x) { /* ... */ }
};

在本例中,x是转发引用,因为&&用于模板内部的函数参数。

现在取这个函数:

struct T {
    template <typename X> void f(X&& x) && { /* ... */ }
};

我预计this将以类似的方式处理;作为转发参考。因此,我希望下面的程序可以正常编译和运行:

#include <iostream>
struct T {
    template <typename X>
    bool operator<(X&& rhs) && {
        std::cout << "&&" << std::endl;
        return true;
    }
};
int main() {
    T t;
    std::cout << (t < T()) << std::endl;
    return 0;
}

但是在使用GCC 4.8.4和6.0.1时,它不会这样做。相反,我得到以下内容:

rvalue.cpp: In function ‘int main()’:
rvalue.cpp:13:25: error: passing ‘T’ as ‘this’ argument of ‘bool T::operator<(X&&) && [with X = T]’ discards qualifiers [-fpermissive]
 std::cout << (t < T()) << std::endl;

似乎this没有被作为转发引用。这是正确的还是错误的?this是否应被视为转发参考?标准的哪一部分规定了这一点?

这里对两个&& s的处理是不同的:

struct T {
    template <typename X> void f(X&& x) && { /* ... */ }
};

你是正确的,x是一个转发引用。但是右边的&&是对象实例的限定条件。在这种情况下,f()只能在对象实例是右值的情况下调用(可能会增加混乱的是,第一个&&x作为转发引用,而第二个&&将隐式对象参数作为右值引用)。即:

T().f(4); // ok
T t;
t.f(4); // error

这与const限定的工作方式相同:

struct X { void f(); };
const X cx;
cx.f(); // error

函数末尾的引用限定符声明,只有当LHS是临时的时候才应该调用operator<。记住,操作符可以像其他成员函数一样调用所以你有

t.operator<(T())

t不是临时的。

如果我们把你的例子改成

std::cout << (T() < t) << std::endl;

然后它工作得很好,因为你正在调用operator<的对象是一个临时对象。

成员operator<() &&只能在rvalue上调用,所以如下:

t < T()

不能工作,因为t不是rvalue左值

下面的代码应该可以工作:

std::move(t) < T()

和this too:

T{} < T{}

请注意,我已经使用了{},因为我更熟悉它们,它们的工作没有太大的惊喜。