我发现了多个关于箭头运算符生成的左值和点运算符生成的左值或右值的问题,但答案不太连贯。
《C++ Primer》一书的第 4.6 章说:
The arrow operator requires a pointer operated and yields an lvalue. The dot operator yields an lvalue if the object from which the member is fetched is an lvalue; otherwise, the result is an rvalue.
作者是否仅指数据成员,或者也指可以用作左值的成员函数?有人可以举一个例子来说明这两个运算符(operator)的行为不同,并解释为什么会这样吗?
如果这个问题已在其他地方得到回答,请原谅。
最佳答案
通过一些例子,这句话更容易理解。我首先从“点”运算符开始。
“点”运算符
让我们首先通过一个简单的 Person
示例来考虑数据成员:
struct Person {
std::string name;
};
一般来说,当人们使用struct
或class
时,您通常会看到它通过命名值访问,该命名值始终会产生标准/预期的左值引用:
auto person = Person{"Foo"}
std::string& name = person.name;
但是,这并不总是必须是左值。通过“点”运算符进行的成员访问将传播正在访问的对象的引用。这意味着如果 person
是右值 (XValue),则可以隐式获取 name
的右值引用:
auto person = Person{"Foo"};
std::string&& name = std::move(person).name;
或作为临时(PRValue):
// Note: using a function call here so that the reference doesn't dangle
auto consume(std::string&&) -> void;
...
consume( Person{"Foo"}.name );
这就是引文所指的内容:
The dot operator yields an lvalue if the object from which the member is fetched is an lvalue; otherwise, the result is an rvalue.
这种值传播在某种程度上也适用于成员函数。自 C++11 以来,可以 ref-qualify member functions -- 它将根据底层对象的引用调用适当的函数:
class Person {
...
auto get_name() && -> std::string&&;
auto get_name() const & -> const std::string&;
...
private:
std::string m_name;
};
...
auto person = Person{...};
person.get_name(); // calls 'get_name() const &'
std::move(person).get_name(); // calls 'get_name() &&'
注意:与访问数据成员不同,函数调用的结果实际上不需要与值类别匹配;这仅用于确定要调用哪个函数作为重载决策的形式。
箭头运算符
对于默认的箭头运算符(例如,不是自定义的operator->
),它只能对指针进行操作。与引用不同,指针不包含指针对象的底层值类别;他们只知道指针本身的值类别。
例如,std::move
一个 Person*
将产生一个 Person*&&
—— 这是指针的右值,但不是底层指向对象的。因此,通过 operator->
取消引用永远不会产生右值,因为永远不知道被指向者是右值。
自定义operator->
定义
箭头运算符也很有趣,因为对于自定义类,可以通过定义 operator->()
来重载它 - 但该运算符仍然会受到与上述相同的问题的限制!
operator->
的任何定义都必须返回一个对象,该对象要么定义 operator->
,或者 是一个指针。这样做是因为 C++ 中的任何表达式 a->b
都会递归调用 operator->
直到到达指针以执行取消引用。从上面我们知道,指针不包含值类别——所以一旦我们到达这一点,我们就无法获得右值。
即使您尝试将其与 ref 限定函数结合起来,例如:
auto operator->() && -> SomeWrapper<T>;
您仍然无法将值类别传播到引用,因为最终它将返回到不包含值类别的指针。
关于c++ - 成员访问运算符生成的左值/右值示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65337493/