声明 RValue 方法(例如 void operation() &&;) 虚拟 C++1x 是不是有意义
Posted
技术标签:
【中文标题】声明 RValue 方法(例如 void operation() &&;) 虚拟 C++1x 是不是有意义【英文标题】:Makes it any sense to declare RValue methods (e.g. void operation() &&;) virtual C++1x声明 RValue 方法(例如 void operation() &&;) 虚拟 C++1x 是否有意义 【发布时间】:2016-02-06 21:56:38 【问题描述】:这可能有点异国情调:
(我正在更新新的 c++ 标准)
在类中声明 RValue 方法是否有意义
例如void operation() &&;
virtual
?我无法想象,因为操作
仅适用于临时对象,例如Base().operation()
或 Derived().operation()
或类似 createObject().operation()
的东西。
表达式createObject()
必须返回一个对象并且
不是引用也不是指针,因为它们都必须
引用左值对象。
由于类型切片,总是调用Base::operation()
。
如果你有一个Derived()
的对象,则调用Derived::operation()
,
尽管如此,它在Base
中是否是虚拟的。
那么,有没有我监督过的案例可以让我理解?
感谢您的启发!
哦,是的,我忘了,RValue 有强制转换:向前移动! 谢谢!
我的发现是: 1.调用一个RValue引用限定 操作 (rqOp() &&),我们总是必须使用 std::forward<..> 除了: Derived().rqOp(); 2. 声明 RValue 引用合格是有意义的 虚拟操作
原因如下: 给定类 Base 和 Derived 具有重载的引用限定操作 rqOp() 和一个非参考合格的称为 op():
class Base
public:
virtual ~Base() = default;
virtual
void rqOp() &&;
virtual void rqOp() &;
virtual void op();
;
class Derived : public Base
public:
//virtual
void rqOp() &&; //override;
virtual void rqOp() & override;
virtual void op() override;
;
和一个重载的函数:
void callOperationF(Base& b)
cout << "callOperationF(Base& b)" << endl;
cout << "b.rqOp();" << endl;
b.rqOp();
void callOperationF(Base&& b)
cout << "callOperationF(Base&& b)" << endl;
cout << "b.rqOp();" << endl;
b.rqOp();
cout << "std::forward<Base&&>(b).rqOp();" << endl;
std::forward<Base&&>(b).rqOp();
cout << "std::forward<Base&&>(b).op();" << endl;
std::forward<Base&&>(b).op();
以及对该重载的一些调用:
cout << "== Derived d;" << endl;
Derived d;
cout << endl;
cout << "== callOperationF(d);" << endl;
callOperationF(d);
cout << endl;
cout << "== callOperationF(Derived());" << endl;
callOperationF(Derived());
产生一个输出:
== Derived d;
== callOperationF(d);
callOperationF(Base& b)
b.rqOp();
Derived::rqOp() &
== callOperationF(Derived());
callOperationF(Base&& b)
b.rqOp();
Derived::rqOp() & ===> 1
std::forward<Base&&>(b).rqOp();
Derived::rqOp() && ===> 2
std::forward<Base&&>(b).op();
Derived::op()
我们可以看到,调用一个 RValue 引用限定 操作(rqOp() &&),我们需要使用forward<..> 在 ===> 1 不调用 RValue 限定! 因为 b 是一个左值表达式。 在 ===> 2 使用 std::forward<..> 正确的方法 被称为也 非引用限定操作 (op()) 是 用 std::forward<...> 正确调用。 如果我们改变接口和 重载 op() 引用合格,它仍然会 调用正确的方法,RValue 引用 qulified 一个。
使用模板化函数,如下所示:
template<class T>
void callOperationT(T&& t)
cout << "callOperationT(T&& t)" << endl;
cout << "t.rqOp()" << endl;
t.rqOp();
cout << "std::forward<T>(t).rqOp();" << endl;
std::forward<T>(t).rqOp();
cout << "std::forward<T>(t).op();" << endl;
std::forward<T>(t).op();
以及对这个函数的一些调用,上面有 Derived d:
cout << endl;
cout << "== callOperationT(d);" << endl;
callOperationT(d);
cout << endl;
cout << "== Base& bRef = d;" << endl;
Base& bRef = d;
cout << "== callOperationT(move(bRef));" << endl;
callOperationT(move(bRef));
cout << endl;
cout << "== callOperationT(Derived());" << endl;
callOperationT(Derived());
产生一个输出:
== callOperationT(d);
callOperationT(T&& t)
t.rqOp()
Derived::rqOp() &
std::forward<T>(t).rqOp();
Derived::rqOp() &
std::forward<T>(t).op();
Derived::op()
== Base& bRef = d;
== callOperationT(move(bRef));
callOperationT(T&& t)
t.rqOp()
Derived::rqOp() &
std::forward<T>(t).rqOp();
Derived::rqOp() && ===> 3
std::forward<T>(t).op();
Derived::op()
== callOperationT(Derived());
callOperationT(T&& t)
t.rqOp()
Derived::rqOp() &
std::forward<T>(t).rqOp();
Derived::rqOp() &&
std::forward<T>(t).op();
Derived::op()
同样的发现:调用一个 RValue 引用限定 操作(rqOp() &&),我们需要使用forward<..> 在 ===> 3 Base::rqOp() && 将被调用,如果 rqOp 不是虚拟的。
谢谢!
【问题讨论】:
像this 这样的东西怎么样,你move
引用base
并在其上调用右值引用限定成员?无论如何,为什么要阻止这种情况呢?
【参考方案1】:
我无法想象,因为该操作只适用于临时对象
不一定。右值引用限定函数要求对象绑定到右值引用。也就是说,您可以有一个函数返回对Base
的右值引用,但其动态类型为Derived
:
struct Base
virtual void f() && std::cout << "Base\n"; ;
virtual ~Base() = default;
;
struct Derived : Base
void f() && override std::cout << "Derived\n";
child;
Base&& Get()
return std::move(child);
int main()
Get().f(); // Derived
【讨论】:
“一个右值引用限定函数要求对象是一个 xvalue(而不是一个纯右值)。”什么? @T.C.什么听起来不合理? OP 认为只有一个临时(又名 prvalue)可以用来调用右值 ref 成员函数,而实际上它可以是任何 xvalue (std::move(x)
) 或 pvalue T()
。
@T.C.大概他的意思是可以在 xvalue 上调用右值引用限定函数【参考方案2】:
我使用它的地方是在派生类实现的基类中创建unique_ptr
复制或移动函数:
class Base
... whatever else
virtual std::unique_ptr<Base> mkuniq() && = 0;
virtual std::unique_ptr<Base> mkuniq() const & = 0;
class Derived : public Base
...
std::unique_ptr<Base> mkuniq() && return std::make_unique<Derived>(std::move(*this));
std::unique_ptr<Base> mkuniq() const & return std::make_unique<Derived>(*this);
这使我可以编写以Base &&
作为参数的其他函数,并在需要时在某个时候转换为unique_ptr<Base>
。然后可以使用未命名的Derived
临时调用所述函数。当然,需要多次调用std::move
才能将已命名的右值引用转换回未命名的右值引用,但在处理右值引用时这是意料之中的。
【讨论】:
以上是关于声明 RValue 方法(例如 void operation() &&;) 虚拟 C++1x 是不是有意义的主要内容,如果未能解决你的问题,请参考以下文章