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

Forwarding references, ref qualifiers and template member functions

取如下成员函数:

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 是否应该被视为转发参考?标准的哪一部分规定了这一点?

函数末尾的引用限定符声明 operator< 仅应在 LHS 为临时对象时调用。请记住,运算符可以像任何其他成员函数一样被调用,所以您拥有的是

t.operator<(T())

并且t不是临时的。

如果我们将您的示例更改为

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

然后它就可以正常工作了,因为您调用 operator< 的对象是一个临时对象。

这里的两个&&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

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

t < T()

不会起作用,因为 t 不是 rvalue — 它是 lvalue.

以下应该有效:

std::move(t) < T()

还有这个:

T{} < T{}

请注意,我使用 {} 是因为我更习惯使用它们,而且它们的工作效果并不令人意外。