为什么这个指针引用是右值?

Why is this reference of a pointer a rvalue?

我有以下基础并继承类:

// Abstract base class Manager.
class Manager
{
public:
  Manager(Task*& _task);
protected:
  // Reference of a pointer to the current task.
  Task*& task;
};

// Abstract base class Task.
class Task
{
  virtual task_rcodes_t run() = 0;
protected:
  uint8_t task_id;
};

// Still abstract class Special_Task.
class Special_Task : public Task
{
public:
  Special_Task();
};

// Class Special_Manager.
class Special_Manager : public Manager
{
public:
  Special_Manager();
protected:
  // Pointer to the current special task.
  Special_Task* task;
};

想法是让任务指针为0,以检测当前没有任务运行。为了共同访问任务和 Special_Task 指针,它们通过引用传递给指针。

为什么我会收到错误消息: "invalid initialization of non-const reference of type 'Task&' from an rvalue of type 'Special_Task*'" 结合: "Symbol 'Manager' could not be resolved"

对于Special_Manager的构造函数:

// Constructor Manager
Manager::Manager(Task*& _task) : task (_task)
{}

// Constructor Special_Manager
Special_Manager::Special_Manager() : Manager(task), task (0)
{}

因为 Special_Task* task 是一个普通的(指针)变量,我不明白为什么它被认为是一个右值?

谢谢!

错误在这里:

Special_Manager::Special_Manager() : Manager(task), task (0)
{}

0 被认为是 rvalueint&& 类型转换为 Task*&& 的类型。这是可能的,因为 0 被认为是指向指针的 cast-able 值的有效形式。但是因为构造函数只采用 Task*&,它不能采用值 0 的强制转换形式,因此编译器拒绝代码。

如果你要创建 const Task*& 类型的构造函数参数,那么代码将会编译,因为 const Task*&Task*&&.[=21= 的类型兼容]

Since Special_Task* task is a normal (pointer) variable, I don't see why it is considered a rvalue?

任何左值都可以通过隐式转换转换为右值。 task 是左值,因为它是 "the name of a variable ... in scope"(参见 cppreference on value categories),并且在您的示例中它被转换为右值。

但在这种情况下,整个 lvalue/rvalue 事情在很大程度上是一个转移注意力的问题。问题是您试图将一种类型的指针分配给另一种类型的指针引用,如错误消息所述:

non-const 类型'Task*&' 引用 的无效初始化来自类型'Special_Task*' 的右值 ]

(顺便说一句,我很想知道 compiler/code 给了你那条消息。我试过的所有 gcc 版本都给出了:[= 的无效初始化82=] 来自 'Task*').

类型右值的 'Task*&' 类型引用

即使 Special_TaskTask 的派生类型,您也不能这样做。它们各自的指针类型不是子类型; Special_Task * 不是 Task *,因此不能为 Task *& 变量分配 Special_Task *。 (一些混淆可能是由于 Special_Task * 可以隐式转换为 Task *,但是,重要的是要注意,在这种情况下,结果指针是右值,而不是左值,这解释了后一条错误消息)。

为了说明为什么不能将 Special_Task * 分配给 Task *& 变量,请考虑以下示例:

// Other_Task is a second derived class of Task:
class Other_Task : public Task { /* ...  */ }

Special_Task st;
Special_Task *p = &st; // ok, p points to st

Task *& tp = p; // if it were allowed: tp references p

Other_Task ot;
tp = &ot;       // now, p points to ot - which is the wrong type

上面的例子说明了为什么不能直接将 Special_Task * 赋值给 Task *& 变量。因此,在您的代码中, Special_Task * 被隐式转换为 Task * 并成为右值,也不能将其分配给 non-const 引用。该示例还显示了为什么 const 引用可以:它会阻止导致 p 指向错误类型的对象的赋值。

回到你的问题:鉴于 Manager 中的 task 不需要作为引用,简单的解决方法是将其声明更改为简单的指针:

Task* task;

并更改构造函数:

Manager(Task* _task);

另一种解决方案(虽然我不推荐)是将类型更改为 const 参考:

Task * const & task;

Manager(Task* const & _task);

哦,还有一件事:

Special_Manager::Special_Manager() : Manager(task), task (0)

这会将 task 的未初始化值传递给 Manager 构造函数,然后 然后 task 初始化为 0。您应该这样写:

Special_Manager::Special_Manager() : Manager(0), task (0)

扩展 davmac 的回答:

  • 如果YX的子类,那么:

    • a reference-to-X真的可以引用a Y。同样,
    • a pointer-to-X可以指向一个Y.

    但是,类型 pointer-to-Xpointer-to-Y 本身并不像 XY 那样相关,所以

    • a pointer-to-pointer-to-X 无法指向 pointer-to- Y(虽然最后的pointer-to-X可以指向一个Y), 和
    • a reference-to-pointer-to-X 不能引用 pointer-to- Y 要么。

比较模板实例,其中尽管 XY 有关系,但 std::vector<X>std::vector<Y> 完全没有关系。


具体来说,reference-to-pointer-to-Task 不能引用 pointer-to- Special_Task.