为什么这个指针引用是右值?
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
被认为是 rvalue
或 int&&
类型转换为 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_Task
是 Task
的派生类型,您也不能这样做。它们各自的指针类型不是子类型; 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 的回答:
如果Y
是X
的子类,那么:
- a reference-to-
X
真的可以引用a Y
。同样,
- a pointer-to-
X
可以指向一个Y
.
但是,类型 pointer-to-X
和 pointer-to-Y
本身并不像 X
和 Y
那样相关,所以
- a pointer-to-pointer-to-
X
无法指向 pointer-to- Y
(虽然最后的pointer-to-X
可以指向一个Y
), 和
- a reference-to-pointer-to-
X
不能引用 pointer-to- Y
要么。
比较模板实例,其中尽管 X
和 Y
有关系,但 std::vector<X>
和 std::vector<Y>
完全没有关系。
具体来说,reference-to-pointer-to-Task
不能引用 pointer-to- Special_Task
.
我有以下基础并继承类:
// 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
被认为是 rvalue
或 int&&
类型转换为 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_Task
是 Task
的派生类型,您也不能这样做。它们各自的指针类型不是子类型; 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 的回答:
如果
Y
是X
的子类,那么:- a reference-to-
X
真的可以引用aY
。同样, - a pointer-to-
X
可以指向一个Y
.
但是,类型 pointer-to-
X
和 pointer-to-Y
本身并不像X
和Y
那样相关,所以- a pointer-to-pointer-to-
X
无法指向 pointer-to-Y
(虽然最后的pointer-to-X
可以指向一个Y
), 和 - a reference-to-pointer-to-
X
不能引用 pointer-to-Y
要么。
- a reference-to-
比较模板实例,其中尽管 X
和 Y
有关系,但 std::vector<X>
和 std::vector<Y>
完全没有关系。
具体来说,reference-to-pointer-to-Task
不能引用 pointer-to- Special_Task
.