0

現在、ostream を使用して端末に書き込む既存のライブラリのポートに取り組んでいます。

ostream はポートの一部として派生しました。

使用される ostream 派生クラスは次のように定義されます。

class owstream: public std::ostream {
public:
    CTerminal * output;
    giac::context * contextptr;
    owstream(CTerminal *, giac::context * contextptr , int = 0);
    virtual ~owstream();
};

これは、通常は整数と倍精度のデータを出力するために使用されます。

問題は、私が取り組んでいるプラットフォームに、カーネル クラッシュを引き起こすバグのある二重印刷ルーチンがあることです。

したがって、場合によっては、次のようにします。

ostream* mystream = new ostream(...);
(*mystream) << 1.23456

カブーム

そのため、次のように、特定のタイプの << 演算子をオーバーライドしようとしました。

ostream* GetStream() { return = new MyOStream(...); }

....

ostream* mystream = GetStream()
mystream << 1.23456;

残念ながら、ostream の operator<< メンバーは仮想ではないため、オーバーライドされた operator<< メンバーを作成すると、呼び出されることはありません。

私は次のようなものでそれを拡張しようとしました:

class owstream: public std::ostream {
    friend std::ostream& operator<<(std::ostream& out, double val);
  public:
    CTerminal * output;
    giac::context * contextptr;
    owstream(CTerminal *, giac::context * contextptr , int = 0);
    virtual ~owstream();
};

extern std::ostream& operator<<(std::ostream &out, double val);

しかし、これは演算子 << があいまいであることに関してコンパイル エラーを引き起こします。明らかに、これは基本 iostream クラスによって既に処理されている型だからです。

これが可能かどうか疑問に思い始めています。

<< 演算子を実装して、特定の既に処理された型が与えられたときの動作をオーバーライドするにはどうすればよいでしょうか?

次のようなことができるようになることを目的としています。

cout << 1.234567

クラッシュしない (明らかに cout を使用しないだろうが、上で定義した GetStream() は cout を返す可能性が非常に高い)

4

2 に答える 2

1

現在のアプローチ/実装には3つの問題があります。

問題#1

最初のパラメーターとして使用std::ostreamして値を返すことができたとしても、正しく機能しません。ostreamこの問題は主に、オーバーロードされた から を返すことに起因しoperator<<ます。最初の値が に送信された後、owstream後続のすべての値が返された に送信されますostream。これにより、元の問題を開始した場所に戻ります。これが適切に機能するためにowstreamは、最初のパラメーターとして取りowstream、オーバーロードされた で返す必要がありますoperator<<

問題#2

もう 1 つの問題はowstream、 が暗黙的に に変換可能であることstd::ostreamです。プロジェクトでの使用方法によってowstreamは、指定したオーバーロードが特定の状況で違いを生まない可能性があります。たとえば、 型のオブジェクトがowstreamを受け入れる関数に渡されたstd::ostream場合、現在発生している問題が発生する可能性があります。private継承を使用することで、これを防ぐことができます。owstreamこれにより、 がとして暗黙的に使用されるのを防ぐことができますstd::ostream。継承を使用すると、元の問題に戻る可能性のあるprivate関数を知らないうちに使用することを防ぐという利点もあります。std::ostreamたとえば、std::ostreamアクセサー関数を使用して明示的に参照を取得できることが絶対に必要です。

問題#3

最後の問題は、などの特定の IO マニピュレータを処理std::ostreamする のオーバーロードが含まれていることです。これらを具体的に処理するためのオーバーロードを提供しない場合、 のオーバーロードが使用され、最初の場所に戻ってしまいます。上記の継承を使用し、マニピュレータを処理するためのオーバーロードを提供しない場合、コンパイルに失敗します。operator<<std::ostreamstd::endlstd::ostreamprivate


解決

以下のソリューションは、 JRGが提供するものと似ておりdouble、 、float、およびstd::ostreamIO マニピュレーターのアクセサー関数とオーバーロードが含まれています。std::coutこれは完全に機能する例であり、簡単にするためにからのストリーム バッファを使用しています。float不十分なライブラリの実装が同様の問題を引き起こす可能性があるため、 のオーバーロードを含めました。また、プライベート継承を使用して、への暗黙的な変換を防ぎstd::ostreamます。

VC++10 と GCC 4.7.2 でテストしました。コンパイラとライブラリがどの程度準拠しているかに応じて、いくつかの調整が必要になる場合があります。

#include <ostream>
#include <iostream>
#include <sstream>

class owstream : private std::ostream
{
public:
    owstream(std::streambuf* sb)
        : std::ostream(sb)
    {}

    // Template based operator...ohhhhhh ahhhhh.
    template <typename T>
    friend owstream& operator<<(owstream&, const T&);

    // Additional overload to handle ostream specific io manipulators 
    friend owstream& operator<<(owstream&, std::ostream& (*)(std::ostream&));

    // Accessor function to get a reference to the ostream
    std::ostream& get_ostream() { return *this; }
};


template <typename T>
inline owstream&
operator<<(owstream& out, const T& value)
{
    static_cast<std::ostream&>(out) << value;
    return out;
}

//  overload for double
template <>
inline owstream&
operator<<(owstream& out, const double& value)
{
    std::stringstream ss;
    ss << value;
    return out << ss.str();
}

//  overload for float
template <>
inline owstream&
operator<<(owstream& out, const float& value)
{
    std::stringstream ss;
    ss << value;
    return out << ss.str();
}

//  overload for std::ostream specific io manipulators
inline owstream&
operator<<(owstream& out, std::ostream& (*func)(std::ostream&))
{
    static_cast<std::ostream&>(out) << func;
    return out;
}

int main()
{
    owstream ows(std::cout.rdbuf());

    ows << std::endl;
    ows << "hello " << 1.0 << " " << 2.0f << std::endl;
}
于 2013-06-16T21:41:02.013 に答える
1

このようなものはどうですか:

template <typename T>
owstream& operator<<(owstream&, const T&);

template <typename T>
inline owstream&
operator<<(owstream& os, const T& val)
{
   std::ostream& stdos = static_cast<std::ostream&>(os);
   stdos << val;
   return os;
}

template <>
inline owstream&
operator<<(owstream& os, const double& val)
{
   std::stringstream ss;
   ss << val;
   os << ss.str();
   return os;
}
于 2013-06-16T13:22:27.570 に答える