ostream 链接,输出顺序

发布于 2024-12-27 16:51:32 字数 810 浏览 1 评论 0原文

我有一个函数,它接受 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

零度℉ 2025-01-03 16:51:32

根据 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)

现在,标准没有指定参数的求值顺序。 未指定。但是您的编译器似乎首先评估第二个参数,这就是为什么它首先打印 "How are you?",将第二个参数评估为 std::ostream& 类型的值code> 然后被传递给上面显示的调用(该值是对象 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 

另请注意,我没有使用显式 em> 演员;相反,std::cout 被隐式转换为指针类型。

希望有帮助。


编写将数据插入到ostream但也可以与运算符<<链接的函数的正确方法是什么?

什么时候取决于你所说的链接是什么意思?显然,以下内容是行不通的(如上所述):

std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!

无论您如何编写 print()

然而,这是明确定义的:

print(std::cout) << X << Y << Z; //well-defined behaviour!

The behavior of your code is unspecified as per the C++ Standard.

Explanation

The following (I removed std::endl for simplicity)

std::cout << "Hello, world!" << print( std::cout ); 

is equivalent to this:

operator<<(operator<<(std::cout, "Hello, World!"), print(std::cout));

which is a function call, passing two arguments:

  • First argument is : operator<<(std::cout, "Hello, World!")
  • Second argument is : 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 object std::cout itself).

Why hexadecimal output?

You get hexadecimal output because the second argument evaluates to std::cout, which is being printed as hexadecimal number, because std::cout implicitly converts into pointer value of void* type, which is why it is printed as hexadecimal number.

Try this:

void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;

It will print the same value for both. For example, this example at ideone prints this:

0x804a044
0x804a044 

Also note that I didn't use explicit cast; rather std::cout is implicitly converted into pointer type.

Hope that helps.


What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?

When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):

std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!

No matter how you write print().

However this is well-defined:

print(std::cout) << X << Y << Z; //well-defined behaviour!
远昼 2025-01-03 16:51:32

原因是 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;
}

另请参阅此答案,了解有关本例中“未指定”实际含义的更多详细信息。

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;

#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;
}

See also this answer for a little more detail on what "unspecified" actually means in this case.

毁我热情 2025-01-03 16:51:32

十六进制输出

在 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 返回能够输出的内容)

Hello, world! How are you?
something returned by print

LIVE示例

Hexadecimal Output

Before C++11, the class std::ostream has a conversion function to void*. Since your print function returns std::ostream&, when evaluating std::cout << print(...), the returned std::ostream lvalue will be implicitly converted to void* 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 an std::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 causes How 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 (assume print returns something able to be outputted)

Hello, world! How are you?
something returned by print

LIVE EXAMPLE

恋你朝朝暮暮 2025-01-03 16:51:32

在你的声明中 std::cout << “你好世界!” <<打印(std::cout)<< std::endl 是否 std::cout << 是未定义的“Hello, world!”发生在 print( std::cout ) 之前或之后。这就是为什么顺序可能不是您所期望的。

十六进制值来自于您也在执行 std::cout << std::coutprint 返回 std::cout,它被馈送到 << 链中)。右侧的 std::cout 被转换为 void * 并打印到输出中。

In your statement std::cout << "Hello, world!" << print( std::cout ) << std::endl it's undefined whether std::cout << "Hello, world!" happens before or after print( 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 returns std::cout which is fed into the << chain). The right hand std::cout is converted to a void * and that's printed to the output.

羁客 2025-01-03 16:51:32

这可以将 print<< 结合起来并控制顺序:

print( std::cout << "Hello, world!" ) << std::endl;

或者,如果您想要使用 << 调用的函数代码>,请参阅约阿希姆的回答。

This would work, to combine print with << and control the order:

print( std::cout << "Hello, world!" ) << std::endl;

Or, if you want a function that's called with <<, see Joachim's answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文