o流链接,输出顺序
ostream chaining, output order
>我有一个函数,它将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
我想了解这里发生了什么。普通函数是否优先于operator<<
,这就是输出顺序颠倒的原因?编写将数据插入ostream
但也可以与operator<<
链接的函数的正确方法是什么?
根据C++标准,代码的行为未指定。
解释
以下内容(为简单起见,我删除了std::endl
(
std::cout << "Hello, world!" << print( std::cout );
相当于这个:
operator<<(operator<<(std::cout, "Hello, World!"), print(std::cout));
这是一个函数调用,传递两个参数:
- 第一个参数是:
operator<<(std::cout, "Hello, World!")
- 第二个参数是:
print(std::cout)
现在,标准没有指定计算参数的顺序。它未指定。但是你的编译器似乎首先计算第二个参数,这就是为什么它首先打印"你好吗?">,将第二个参数评估为类型 std::ostream&
的值,然后将其传递给上面显示的调用(该值是对象本身std::cout
(。
为什么选择十六进制输出?
你会得到十六进制输出,因为第二个参数的计算结果为 std::cout
,它被打印为十六进制数,因为std::cout
隐式转换为void*
类型的指针值,这就是它打印为十六进制数的原因。
试试这个:
void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;
它将为两者打印相同的值。例如,ideone 的此示例打印了以下内容:
0x804a044
0x804a044
另请注意,我没有使用显式强制转换;而是隐式转换为指针类型std::cout
。
希望有帮助。
<小时 />编写将数据插入
ostream
但也可以与operator<<
链接的函数的正确方法是什么?
当它取决于你所说的链接是什么意思时?显然,以下内容不起作用(如上所述(:
std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!
不管你怎么写print()
.
但是,这是明确定义的:
print(std::cout) << X << Y << Z; //well-defined behaviour!
原因是你的 print(( 函数将在语句的其余部分之前被计算并返回对 cout 的引用,然后实际打印为指针(cout <<cout(。这种计算顺序实际上是未指定的行为,但编译器似乎就是这种情况。
至于定义一个流感知"函数",该函数实际上定义了具有相同功能的行为,这将起作用;
#include <iostream>
template <class charT, class traits>
std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os )
{
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print << std::endl;
}
另请参阅此答案,了解有关"未指定"在这种情况下实际含义的更多详细信息。
十六进制输出
在 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 开始,算子<<
操作数的计算顺序严格从左到右,重载算子的操作数与 bulit-in 一个的操作数共享相同的求值顺序(在此处查看更多详细信息(。所以你的程序将始终获得输出(假设print
返回能够输出的东西(
Hello, world! How are you?
something returned by print
现场示例
在您的语句中std::cout << "Hello, world!" << print( std::cout ) << std::endl
不确定std::cout << "Hello, world!"
发生在print( std::cout )
之前还是之后。这就是为什么订单可能不是您所期望的。
十六进制值来自你也在做std::cout << std::cout
的事实(print
返回std::cout
,它被输入到<<
链中(。右侧std::cout
将转换为void *
并打印到输出中。
这将起作用,将print
与<<
相结合并控制顺序:
print( std::cout << "Hello, world!" ) << std::endl;
或者,如果你想要一个用<<
调用的函数,请参阅约阿希姆的答案。
- 如何在 C++ 中将从文本文件中读取的元素推送和弹出到数组中,并按 Revserse 顺序输出堆栈?
- 堆排序,我无法弄清楚我的代码出了什么问题,输出顺序不正确
- C++ 以相反的顺序输出文本文件
- 函数以相反的顺序输出输入问题,并改进算法以解释相等的数字
- `sTD :: sample()的输出序列是否遵循输入序列的顺序
- cout 和 cerr 的控制台输出顺序错误
- C 的输出顺序错误
- 以特定顺序输出地图
- 以正确的顺序输出队列
- 输出未按正确的顺序打印
- 更改声明顺序时输出不正确
- VC++编译器输出顺序
- 为什么 bool 显示正确的位顺序,而直接输出移位运算结果却不显示?
- C++输出顺序
- 数字的基本表示-输出顺序相反
- fprintf和WriteConsole的输出顺序相反
- o流链接,输出顺序
- 在c++中使用map时输出顺序错误
- 检查输出顺序是否正确
- 如何在C++中反转输出顺序?(有或没有递归)