ostream 链接,输出顺序
我有一个函数,它接受 ostream 引用作为参数,将一些数据写入流,然后返回对同一流的引用,如下所示:
#include <iostream>
std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}
这段代码的输出是:
How are you?
Hello, world!0x601288
但是,如果我将链接表达式分成两个语句,这样
int main() {
std::cout << "Hello, world!";
std::cout << print( std::cout ) << std::endl;
}
我至少在输出中得到正确的顺序,但仍然得到一个十六进制值:
Hello, world! How are you?
0x600ec8
我想了解这里发生了什么。普通函数是否优先于运算符<<,这就是输出顺序相反的原因?编写将数据插入 ostream
但也可以与 operator<<
链接的函数的正确方法是什么?
I have a function that takes an ostream
reference as an argument, writes some data to the stream, and then returns a reference to that same stream, like so:
#include <iostream>
std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}
The output of this code is:
How are you?
Hello, world!0x601288
However, if I separate the chaining expressions into two statements, like this
int main() {
std::cout << "Hello, world!";
std::cout << print( std::cout ) << std::endl;
}
then I at least get the proper order in the output, but still get a hex value:
Hello, world! How are you?
0x600ec8
I would like to understand what's going on here. Does a normal function take precedence over operator<<
, and that's why the output order reverses? What is the proper way to write a function that inserts data into an ostream
but that can also chain with operator<<
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
根据 C++ 标准,代码的行为未指定。
解释
以下内容(为了简单起见,我删除了 std::endl)
相当于:
这是一个函数调用,传递两个参数:
print(std::cout)
现在,标准没有指定参数的求值顺序。 未指定。但是您的编译器似乎首先评估第二个参数,这就是为什么它首先打印 "How are you?",将第二个参数评估为
std::ostream& 类型的值code> 然后被传递给上面显示的调用(该值是对象
std::cout
本身)。为什么要输出十六进制?
您会得到十六进制输出,因为第二个参数的计算结果为
std::cout
,它被打印为十六进制数字,因为std::cout
隐式转换为的指针值>void*
类型,这就是为什么它被打印为十六进制数。试试这个:
它将为两者打印相同的值。例如,ideone 中的示例打印以下内容:
另请注意,我没有使用显式 em> 演员;相反,std::cout 被隐式转换为指针类型。
希望有帮助。
什么时候取决于你所说的链接是什么意思?显然,以下内容是行不通的(如上所述):
无论您如何编写
print()
。然而,这是明确定义的:
The behavior of your code is unspecified as per the C++ Standard.
Explanation
The following (I removed
std::endl
for simplicity)is equivalent to this:
which is a function call, passing two arguments:
operator<<(std::cout, "Hello, World!")
print(std::cout)
Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type
std::ostream&
which then gets passed to the call shown above (that value is the objectstd::cout
itself).Why hexadecimal output?
You get hexadecimal output because the second argument evaluates to
std::cout
, which is being printed as hexadecimal number, becausestd::cout
implicitly converts into pointer value ofvoid*
type, which is why it is printed as hexadecimal number.Try this:
It will print the same value for both. For example, this example at ideone prints this:
Also note that I didn't use explicit cast; rather
std::cout
is implicitly converted into pointer type.Hope that helps.
When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):
No matter how you write
print()
.However this is well-defined:
原因是 print() 函数将在语句的其余部分之前进行评估,并返回对 cout 的引用,然后将其实际打印为指针(cout << cout)。这种评估顺序实际上是未指定的行为,但似乎是您的编译器的情况。
至于定义一个流感知的“函数”,它实际上已经定义了具有相同功能的行为,这是可行的;
另请参阅此答案,了解有关本例中“未指定”实际含义的更多详细信息。
The reason is that your print() function will be evaluated before the rest of the statement and return a reference to cout which is then actually printed as a pointer (cout << cout). This order of evaluation is actually unspecified behavior, but seems to be the case with your compiler.
As for defining a stream aware "function" that actually has defined behavior with the same functionality, this would work;
See also this answer for a little more detail on what "unspecified" actually means in this case.
十六进制输出
在 C++11 之前,类
std::ostream
具有到void*
的转换函数。由于您的print
函数返回std::ostream&
,因此在评估std::cout << print(...)
时,返回的 std::ostream 左值将隐式转换为 void*,然后作为指针值输出。这就是为什么有十六进制输出。从 C++11 开始,此转换函数被显式转换函数替换到
bool
,因此尝试输出std::ostream
对象的格式不正确。求值顺序
在 C++17 之前,重载运算符被视为函数调用来分析求值顺序,并且函数调用的不同参数的求值顺序是未指定的。因此,
print
函数首先被求值也就不足为奇了,这会导致How are you?
首先被输出。从 C++17 开始,运算符
<<
的操作数的求值顺序严格从左到右,重载运算符的操作数与内置运算符的操作数共享相同的求值顺序(请参阅此处了解更多详细信息)。因此,您的程序将始终获得输出(假设print
返回能够输出的内容)LIVE示例
Hexadecimal Output
Before C++11, the class
std::ostream
has a conversion function tovoid*
. Since yourprint
function returnsstd::ostream&
, when evaluatingstd::cout << print(...)
, the returnedstd::ostream
lvalue will be implicitly converted tovoid*
and then be outputted as a pointer value. This is why there is a hexadecimal output.Since C++11, this conversion function is replaced by an explicit conversion function to
bool
, so trying to output anstd::ostream
object becomes ill-formed.Evaluation Order
Before C++17, overloaded operator is considered a function call for analyzing evaluation order, and evaluation order of different arguments of a function call is unspecified. So it is not strange that the
print
function is evaluated firstly, which causesHow are you?
is outputted firstly.Since C++17, the evaluation order of operands of operator
<<
is strictly from left to right, and operands of overloaded operator share the same evaluation order as those of the bulit-in one (see more details here). So your program will always get the output (assumeprint
returns something able to be outputted)LIVE EXAMPLE
在你的声明中
std::cout << “你好世界!” <<打印(std::cout)<< std::endl
是否 std::cout << 是未定义的“Hello, world!”发生在print( std::cout )
之前或之后。这就是为什么顺序可能不是您所期望的。十六进制值来自于您也在执行
std::cout << std::cout
(print
返回std::cout
,它被馈送到<<
链中)。右侧的std::cout
被转换为void *
并打印到输出中。In your statement
std::cout << "Hello, world!" << print( std::cout ) << std::endl
it's undefined whetherstd::cout << "Hello, world!"
happens before or afterprint( std::cout )
. That's why the order may not be what you expect.The hex value comes from the fact that you're also doing
std::cout << std::cout
(print
returnsstd::cout
which is fed into the<<
chain). The right handstd::cout
is converted to avoid *
and that's printed to the output.这可以将
print
与<<
结合起来并控制顺序:或者,如果您想要使用
<<
调用的函数代码>,请参阅约阿希姆的回答。This would work, to combine
print
with<<
and control the order:Or, if you want a function that's called with
<<
, see Joachim's answer.