C++ 将某些内容打印到 std::ostream 并返回 std::ostream 的函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1087927/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:44:54  来源:igfitidea点击:

Function that prints something to std::ostream and returns std::ostream?

c++outputstreamostream

提问by Frank

I want to write a function that outputs something to a ostreamthat's passed in, and return the stream, like this:

我想编写一个函数,向ostream传入的a 输出一些内容,并返回流,如下所示:

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

It would be convenient to print the value like this and embed the function call in the output operator chain, like I did in main().

像这样打印值并将函数调用嵌入到输出运算符链中会很方便,就像我在main().

It doesn't work, however, and prints this:

然而,它不起作用,并打印:

$ ./a.out
12Value: 0x6013a8

The desired output would be this:

所需的输出是这样的:

Value: 12

How can I fix this? Do I have to define an operator<<instead?

我怎样才能解决这个问题?我必须定义一个operator<<吗?

UPDATE:Clarified what the desired output would be.

更新:阐明了所需的输出是什么。

UPDATE2:Some people didn't understand why I would print a number like that, using a function instead of printing it directly. This is a simplified example, and in reality the function prints a complex object rather than an int.

UPDATE2:有些人不明白为什么我会打印这样的数字,使用函数而不是直接打印它。这是一个简化的示例,实际上该函数打印的是一个复杂的对象而不是int.

回答by Steve Jessop

You can't fix the function. Nothing in the spec requires a compiler to evaluate a function call in an expression in any particular order with respect to some unrelated operator in the same expression. So without changing the calling code, you can't make MyPrint()evaluate after std::cout << "Value: "

您无法修复该功能。规范中没有任何内容要求编译器以任何特定顺序对表达式中的函数调用求值,该顺序与同一表达式中的某些不相关运算符有关。所以不改变调用代码,你不能在MyPrint()之后进行评估std::cout << "Value: "

Left-to-right order is mandated for expressions consisting of multiple consecutive << 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.

对于由多个连续的 << 运算符组成的表达式,从左到右的顺序是强制性的,这样就可以了。operator<< 返回流的要点是,当运算符被链接时,每个运算符的 LHS 由其左侧运算符的评估提供。

You can't achieve the same thing with free function calls because they don't have a LHS. MyPrint()returns an object equal to std::cout, and so does std::cout << "Value: ", so you're effectively doing std::cout << std::cout, which is printing that hex value.

你不能用免费的函数调用来达到同样的目的,因为它们没有 LHS。MyPrint()返回一个等于 的对象std::cout, 也是如此std::cout << "Value: ",因此您正在有效地执行std::cout << std::cout,即打印该十六进制值。

Since the desired output is:

由于所需的输出是:

Value: 12

the "right" thing to do is indeed to override operator<<. This frequently means you need to either make it a friend, or do this:

“正确”的做法确实是覆盖 operator<<。这通常意味着您需要与它成为朋友,或者这样做:

class WhateverItIsYouReallyWantToPrint {
    public:
    void print(ostream &out) const {
        // do whatever
    }
};

ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
    obj.print(out);
}

If overriding operator<<for your class isn't appropriate, for example because there are multiple formats that you might want to print, and you want to write a different function for each one, then you should either give up on the idea of operator chaining and just call the function, or else write multiple classes that take your object as a constructor parameter, each with different operator overloads.

如果operator<<您的类的覆盖不合适,例如因为您可能想要打印多种格式,并且您想为每种格式编写不同的函数,那么您应该放弃运算符链接的想法,而只是调用函数,或者编写多个类,将您的对象作为构造函数参数,每个类都有不同的运算符重载。

回答by rlbond

You want to make MyPrint a class with friend 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;
}

This method requires you to insert the MyPrint object into the stream of your choice. If you REALLY need the ability to change which stream is active, you can do this:

此方法要求您将 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;
}

回答by Max Lybbert

You have two options. The first, using what you already have is:

你有两个选择。首先,使用你已经拥有的是:

std::cout << "Value: ";
MyPrint(12, &std::cout);
std::cout << std::endl;

The other, which is more C++-like, is to replace MyPrint()with the appropriate std::ostream& operator<<. There's already one for int, so I'll do one just a tad more complex:

另一个更像 C++,是MyPrint()用适当的std::ostream& operator<<. 已经有一个 for 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;
}

回答by Gerald

There's no way to do what you're expecting there because of the order the functions are evaluated in.

由于函数的计算顺序,没有办法在那里做你期望的事情。

Is there any particular reason you need to write directly to the ostream like that? If not, just have MyPrint return a string. If you want to use a stream inside MyPrint to generate the output, just use a strstream and return the result.

是否有任何特殊原因需要像这样直接写入 ostream?如果没有,只需让 MyPrint 返回一个字符串。如果您想在 MyPrint 中使用流来生成输出,只需使用 strstream 并返回结果。

回答by Seth Johnson

After changing the pointer to a reference, you can do this:

将指针更改为引用后,您可以执行以下操作:

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

The syntax for MyPrintis essentially that of an unrolled operator<<but with an extra argument.

for 的语法MyPrint本质上是一个展开operator<<但带有额外参数的语法。

回答by Seth Johnson

First, there is no reason not to pass in the ostreamby reference rather than by a pointer:

首先,没有理由不ostream通过引用而不是通过指针传递:

std::ostream& MyPrint(int val, std::ostream& out) {
  out << val;
  return out;
}

If you really don't want to use std::ostream& operator<<(std::ostream& os, TYPE), you can do this:

如果你真的不想使用std::ostream& operator<<(std::ostream& os, TYPE),你可以这样做:

int main(int argc, char** argv){
    std::cout << "Value: ";
    MyPrint(12, std::cout) << std::endl;
    return 0;
}

回答by Seth Johnson

In your case the answer is obviously:

在你的情况下,答案显然是:

 std::cout << "Value: " << 12 << std::endl;

If that isn't good enough, please explain what output you want to see.

如果这还不够好,请说明您想看到什么输出。