10

我想编写一个函数,将某些内容输出到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;
}

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

但是,它不起作用,并打印:

$ ./a.out
12Value: 0x6013a8

所需的输出将是这样的:

Value: 12

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

更新:澄清了所需的输出。

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

4

7 回答 7

13

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

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

你不能用自由函数调用来实现同样的事情,因为它们没有 LHS。MyPrint()返回一个等于 的对象std::cout,因此也是如此std::cout << "Value: ",因此您实际上std::cout << std::cout是在打印该十六进制值。

由于所需的输出是:

Value: 12

“正确”的做法确实是重写 operator<<。这通常意味着您需要交朋友,或者这样做:

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

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

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

于 2009-07-06T16:48:06.273 回答
6

你想让 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;
}

此方法要求您将 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;
}
于 2009-07-06T16:35:27.673 回答
4

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

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

另一个更类似于 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;
}
于 2009-07-06T17:43:10.390 回答
1

由于函数的评估顺序,没有办法做你期望的事情。

有什么特别的原因需要像这样直接写入 ostream 吗?如果没有,只需让 MyPrint 返回一个字符串。如果要使用 MyPrint 中的流来生成输出,只需使用 strstream 并返回结果。

于 2009-07-06T17:13:32.277 回答
0

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

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

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

int main(int argc, char** argv){
    std::cout << "Value: ";
    MyPrint(12, std::cout) << std::endl;
    return 0;
}
于 2009-07-06T16:38:36.870 回答
0

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

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

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

于 2009-07-06T17:55:38.383 回答
-1

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

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

如果这还不够好,请说明您希望看到的输出。

于 2009-07-06T16:44:02.460 回答