简体   繁体   English

将内容输出到std :: ostream并返回std :: ostream的函数?

[英]Function that prints something to std::ostream and returns std::ostream?

I want to write a function that outputs something to a ostream that's passed in, and return the stream, like this: 我想写一个函数,输出一些传入的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;
}

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. 更新2:有些人不明白为什么我会打印这样的数字,使用函数而不是直接打印它。 This is a simplified example, and in reality the function prints a complex object rather than an int . 这是一个简化的示例,实际上该函数打印的是复杂对象而不是int

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: " 因此,在不更改调用代码的情况下,您无法在std::cout << "Value: "后进行MyPrint()评估。

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. 操作符<<返回流的点是当操作符被链接时,每个操作符的LHS由操作符的左侧评估提供。

You can't achieve the same thing with free function calls because they don't have a LHS. 您无法通过自由函数调用实现相同的功能,因为它们没有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. 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: 这通常意味着你需要让它成为朋友,或者这样做:

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<<不合适,例如因为您可能想要打印多种格式,并且您想为每个格式编写不同的函数,那么您应该放弃运算符的概念链接并只调用该函数,或者编写多个类,将您的对象作为构造函数参数,每个类具有不同的运算符重载。

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. 此方法要求您将MyPrint对象插入到您选择的流中。 If you REALLY need the ability to change which stream is active, you can do this: 如果您真的需要能够更改哪个流处于活动状态,则可以执行以下操作:

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

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<< . 另一个更像C ++的是,用适当的std::ostream& operator<<替换MyPrint() There's already one for int , so I'll do one just a tad more complex: 已经有一个用于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;
}

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? 有没有什么特别的理由需要像这样直接写入ostream? If not, just have MyPrint return a string. 如果没有,只需让MyPrint返回一个字符串。 If you want to use a stream inside MyPrint to generate the output, just use a strstream and return the result. 如果要在MyPrint中使用流来生成输出,只需使用strstream并返回结果。

First, there is no reason not to pass in the ostream by 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;
}

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 MyPrint is essentially that of an unrolled operator<< but with an extra argument. MyPrint的语法基本上是展开的operator<<但带有额外的参数。

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. 如果这还不够好,请解释您想要看到的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM