我想编写一个函数,将一些内容输出到传入的
ostream
,并返回流,如下所示:
std::ostream& MyPrint(int val, std::ostream* out) {
*out << val;
return *out;
}
int main(int argc, char** argv){
std::cout << "Value: " << MyPrint(12, &std::cout) << std::endl;
return 0;
}
像这样打印值并将函数调用嵌入到输出运算符链中会很方便,就像我在
main()
中所做的那样。
但是它不起作用,并打印出以下内容:
$ ./a.out
12Value: 0x6013a8
期望的输出是这样的:
Value: 12
我该如何解决这个问题?我必须定义一个
operator<<
吗?
更新:阐明了所需的输出是什么。
UPDATE2: 有些人不明白为什么我会使用函数而不是直接打印这样的数字。这是一个简化的示例,实际上该函数打印一个复杂的对象而不是一个
int
。
您无法修复该功能。规范中没有任何内容要求编译器相对于同一表达式中的某些不相关运算符以任何特定顺序评估表达式中的函数调用。因此,在不更改调用代码的情况下,您无法使
MyPrint()
在 std::cout << "Value: "
之后进行评估
由多个连续组成的表达式强制从左到右顺序 << operators, so that will work. The point of operator<< returning the stream is that when operators are chained, the LHS of each one is supplied by the evaluation of the operator to its left.
使用自由函数调用无法实现同样的效果,因为它们没有 LHS。
MyPrint()
返回一个等于 std::cout
的对象,std::cout << "Value: "
也是如此,因此您实际上正在执行 std::cout << std::cout
,即打印该十六进制值。
由于所需的输出是:
Value: 12
“正确”的做法确实是重写运算符<<. This frequently means you need to either make it a friend, or do this:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
如果为您的类覆盖
operator<<
不合适,例如因为您可能想要打印多种格式,并且您想为每种格式编写不同的函数,那么您应该放弃以下想法运算符链接并仅调用该函数,或者编写多个类,将您的对象作为构造函数参数,每个类都有不同的运算符重载。
您想让 MyPrint 与好友操作员一起上课<<:
class MyPrint
{
public:
MyPrint(int val) : val_(val) {}
friend std::ostream& operator<<(std::ostream& os, const MyPrint& mp)
{
os << mp.val_;
return os;
}
private:
int val_;
};
int main(int argc, char** argv)
{
std::cout << "Value: " << MyPrint(12) << std::endl;
return 0;
}
此方法要求您将 MyPrint 对象插入到您选择的流中。如果您确实需要更改哪个流处于活动状态,您可以这样做:
class MyPrint
{
public:
MyPrint(int val, std::ostream& os) : val_(val), os_(os) {}
friend std::ostream& operator<<(std::ostream& dummy, const MyPrint& mp)
{
mp.os_ << mp.val_;
return os_;
}
private:
int val_;
std::ostream& os_
};
int main(int argc, char** argv)
{
std::cout << "Value: " << MyPrint(12, std::cout) << std::endl;
return 0;
}
你有两个选择。首先,使用您已有的:
std::cout << "Value: ";
MyPrint(12, &std::cout);
std::cout << std::endl;
另一种更类似于 C++,是将
MyPrint()
替换为适当的 std::ostream& operator<<
。已经有一个 int
了,所以我会做一个稍微复杂一点的:
#include <iostream>
struct X {
int y;
};
// I'm not bothering passing X as a reference, because it's a
// small object
std::ostream& operator<<(std::ostream& os, const X x)
{
return os << x.y;
}
int main()
{
X x;
x.y = 5;
std::cout << x << std::endl;
}
由于函数评估的顺序,无法执行您所期望的操作。
有什么特殊原因需要像这样直接写入 ostream 吗?如果没有,只需让 MyPrint 返回一个字符串。如果您想在 MyPrint 中使用流来生成输出,只需使用 strstream 并返回结果即可。
首先,没有理由不通过引用而不是指针传递
ostream
:
std::ostream& MyPrint(int val, std::ostream& out) {
out << val;
return out;
}
如果你实在不想用
std::ostream& operator<<(std::ostream& os, TYPE)
,你可以这样做:
int main(int argc, char** argv){
std::cout << "Value: ";
MyPrint(12, std::cout) << std::endl;
return 0;
}
将指针更改为引用后,您可以执行以下操作:
#include <iostream>
std::ostream& MyPrint(int val, std::ostream& out) {
out << val;
return out;
}
int main(int, char**) {
MyPrint(11, std::cout << "Value: ") << std::endl;
return 0;
}
MyPrint
的语法本质上是展开的operator<<
的语法,但带有一个额外的参数。
自 C++11 起,将返回对 ostream 的引用的函数与另一个 ostream 链接起来是不正确的。例如,请参阅此答案。
原因是因为自 C++11 以来,不再存在 ostream 到
void *
的隐式转换。
就您而言,答案显然是:
std::cout << "Value: " << 12 << std::endl;
如果这还不够好,请解释你想看到什么输出。