10

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

このように値を出力し、で行ったように、関数呼び出しを出力演算子チェーンに埋め込むと便利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ます。つまり、その16進値を出力します。

目的の出力は次のとおりです。

Value: 12

「正しい」ことは、実際に演算子<<をオーバーライドすることです。これは頻繁にあなたがそれを友達にするか、これをする必要があることを意味します:

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

2つのオプションがあります。1つ目は、すでに持っているものを使用することです。

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

もう1つは、C ++に似MyPrint()ていますが、適切なに置き換えることstd::ostream& operator<<です。にはすでに1つある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;
}

の構文MyPrintは基本的に展開されoperator<<たものですが、追加の引数があります。

于 2009-07-06T17:55:38.383 に答える
-1

あなたの場合、答えは明らかに次のとおりです。

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

それでも不十分な場合は、どの出力を見たいか説明してください。

于 2009-07-06T16:44:02.460 に答える