我了解到我们可以重载operator<<,如下所示:
class Person
{
public:
friend std::ostream& operator<<(std::ostream& os, const Person& obj);
};我绝对理解参数类型被引用的原因。例如,第一个参数是引用,因为不能复制流,而第二个参数是引用,因为我们希望反映对原始对象所做的更改(如果有operator>>的话)。我知道,由于我们在第二个参数中有一个低级const,它的状态不能改变,通过使用引用,我们避免了复制。
我的问题是,对于第一个参数,我们可以(也应该)使用rvalue引用而不是lvalue引用,如下所示:
friend std::ostream& operator<<(std::ostream&& os, const Person& obj); //note the first parameter is rvalue-reference我们是否有理由不做上面所示的事情?更重要的是,如果我们这样做会发生什么。
同样,我的第二个问题是,我们是否可以将返回类型改为std::ostream&&而不是std::ostream&。在这种情况下,会发生什么/发生什么变化。
PS:我正在学习C++,出于好奇我问了这个问题。那就是,加深我对参考文献和超载的认识。
发布于 2022-03-18 14:06:08
如果尝试编写如下内容,程序将不会编译(@PaulMcKenzie的注释中已经提到了这一点):
#include <iostream>
#include <ostream>
struct Person {
int x = 0;
};
std::ostream& operator<<(std::ostream&& os, const Person& obj)
{
return os << obj.x;
}
int main()
{
Person p;
std::cout << p;
}但是,您可以通过将main中的最后一行更改为
std::move(std::cout) << p; // don't do this in real code然后,该程序将编译并输出0。然而,在此之后,std::cout流将处于移出状态,不应该再使用了。
对于其中的一些评论,似乎对r值引用是什么有误解。有些人似乎认为这只是一个更好的l值引用,我们在C++11之前无法访问它。
L-值引用指的是可以在表达式左手边使用的东西.您可以将其看作是对实际对象的引用,该对象可以更改并分配给等等。另一方面,r值引用是指一个临时对象,某个东西,可以在任务的右侧使用。
假设您有两个带有以下签名的operator<<重载。
std::ostream& operator<<(std::ostream& os, const Person& obj);
std::ostream& operator<<(std::ostream&& os, const Person& obj);规则是,第一个接受l值或r值引用.后者只接受r值引用。如果我们用l-值调用操作符(std::cout就是这方面的一个例子),那么将使用第一个重载。如果我们用r值(如std::move(std::cout))调用操作符,则使用第二个操作符。您可以省略r值引用重载,在任何情况下都会选择第一个重载,但是如果要使用l值调用操作符,则不能忽略第一个重载。但是,使用l值调用运算符是您几乎总是想要的:
std::cout << p; // will not compile if there is only an r-value reference overload那么r值引用的用例是什么呢?它们用于实现对象上的移动语义。R值引用用于引用对象,这些对象在当前语句之后不再有效(它们没有持久性)。虽然理论上您可以移动std::cout流,就像上面所示的那样,但这一点也没有用。流是指用作具有长生存期的对象,而不是临时对象。
最后,回答您的问题:您不应该这样做,因为流通常不被用作临时对象。如果您真的想向<<操作符提供r值引用重载,那么请继续,但是也为std::cout << p;的正常用例提供了一个l值重载。
发布于 2022-08-04 13:40:34
我的问题是,对于第一个参数,我们可以(也应该)使用rvalue引用而不是lvalue引用,如下所示: 朋友std::ostream& operator<<(std::ostream&& os,const & obj);//注意第一个参数是rvalue-引用
这在技术上是可能的(有一些限制),但肯定是非常奇怪的事情。使用rvalue引用通常意味着对象将被“消耗”(例如,从移出),并且不应该在以后的操作中使用。但是,一般情况下,写入流并不消耗它;流仍然可以用于后续的写入。
发布于 2022-03-18 14:02:59
没有任何技术上的原因可以解释为什么你不能这样做。但是,如果您这样做了,则不会与定义ostream运算符的所有其他东西进行互操作。
如果输入是ostream &&,那么就不能在左边有一个lvalue流
Person p;
std::cout << p // can't bind std::cout to ostream&&将rvalue引用返回给您通过lvalue引用接收到的内容是不礼貌的。
std::ostream&& operator<<(std::ostream& os, const Person& obj) {
// something involving obj
return std::move(os); // stealing something that shouldn't be stolen!
}如果希望有一个带有临时ostream的表达式,则可以。标准库定义模板接受rvalue流,应用等效的lvalue流操作,并移动-返回该流。
https://stackoverflow.com/questions/71527081
复制相似问题