声明 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 &amp;&amp; 作为参数的其他函数,并在需要时在某个时候转换为unique_ptr&lt;Base&gt;。然后可以使用未命名的Derived 临时调用所述函数。当然,需要多次调用std::move 才能将已命名的右值引用转换回未命名的右值引用,但在处理右值引用时这是意料之中的。

【讨论】:

以上是关于声明 RValue 方法(例如 void operation() &&;) 虚拟 C++1x 是不是有意义的主要内容,如果未能解决你的问题,请参考以下文章

什么是void method

void()、逗号运算符 (operator,) 和不可能的 (?) 重载

void operator()()的功能

C# WebApi之接口返回类型详解

为啥不使用强制转换语法调用“operator void”?

C++,在函数中采用 const lvalue 和 rvalue 引用