2009-07-15 6 views
48

私は、オペレータに< <のstd ::演算子をオーバーロードするときENDLが未知のタイプのものであり、<<

template <Typename T> 
UIStream& operator<<(const T); 

UIStream my_stream; 
my_stream << 10 << " heads"; 

作品が、オーバーロードmy_stream << endlを動作させるための回避策はありますか?

+0

UIStreamについては何も知らず、それは少しはコメントすることは困難です。 –

+10

しかし、あなたは道を見つけました。 :) – notJim

答えて

64

std::endlは関数であり、std::coutoperator<<を実装して、std::endlと同じシグネチャを持つ関数ポインタを取ることでそれを利用します。

そこに関数を呼び出し、戻り値を転送します。ここで

は、コード例です:

#include <iostream> 

struct MyStream 
{ 
    template <typename T> 
    MyStream& operator<<(const T& x) 
    { 
     std::cout << x; 

     return *this; 
    } 


    // function that takes a custom stream, and returns it 
    typedef MyStream& (*MyStreamManipulator)(MyStream&); 

    // take in a function with the custom signature 
    MyStream& operator<<(MyStreamManipulator manip) 
    { 
     // call the function, and return it's value 
     return manip(*this); 
    } 

    // define the custom endl for this stream. 
    // note how it matches the `MyStreamManipulator` 
    // function signature 
    static MyStream& endl(MyStream& stream) 
    { 
     // print a new line 
     std::cout << std::endl; 

     // do other stuff with the stream 
     // std::cout, for example, will flush the stream 
     stream << "Called MyStream::endl!" << std::endl; 

     return stream; 
    } 

    // this is the type of std::cout 
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType; 

    // this is the function signature of std::endl 
    typedef CoutType& (*StandardEndLine)(CoutType&); 

    // define an operator<< to take in std::endl 
    MyStream& operator<<(StandardEndLine manip) 
    { 
     // call the function, but we cannot return it's value 
     manip(std::cout); 

     return *this; 
    } 
}; 

int main(void) 
{ 
    MyStream stream; 

    stream << 10 << " faces."; 
    stream << MyStream::endl; 
    stream << std::endl; 

    return 0; 
} 

うまくいけば、これはあなたにこれらのものがどのように動作するかのより良いアイデアを提供します。

+3

私は私の答えを改善することができますので、あなたがダウンしたときにコメントを残してください。 – GManNickG

+4

私はdownvoteをしませんでしたが、ここでは欠落している重要な情報があります:std :: endlは関数ではなくテンプレート関数です。これは、演算子<< overload as: 'template mystream&operator <<(T&(* fp)(T&))'(この署名はすべてのSTL 'basic_stream <>'を受け入れる一般的なマニピュレータを定義しようとすると、 ios_base'と 'basic_ios <>'マニピュレータ)、コンパイラはそれ自身のテンプレートであり、Tの意味を定義することができないので、テンプレートに対してstd :: endlをマッチさせることができません。 –

+1

ありがとう!これは別の質問に答えるのを助けました。 http://stackoverflow.com/questions/2196155 –

4

IOStreamsを拡張するためのより良い方法については、hereを参照してください。 (ちょっと古い、VC 6に合わせて作られているので、塩の穀粒でそれを取らなければならない)

ポイントは、ファンクターを動作させるためのもので、endl、どちらも "\ n"とフラッシュを出力するfunctor)では、完全なostreamインタフェースを実装する必要があります。

3

stdストリームは、仮想メソッドがないのでサブクラス化されないように設計されているので、あまりにも遠すぎるとは思わないでしょう。あなたは、作業を行うためにstd :: ostreamを集約することができます。

あなたはそのようなendlとしてマニピュレータが

UStream& operator<<(UStream&, UStream& (*f)(UStream&)); 

または

UStream& UStream::operator<<(UStream& (*f)(UStream&)); 
すなわち、どのように処理されるかであるとして関数へのポインタを取る operator<<のバージョンを実装する必要が endl作業を行うには

今すぐstd::endlはstd :: basic_ostreamへの参照を受け取って返す関数です。ストリームで直接動作しないように、あなた自身のバージョンを作る必要があります。 e std::endlバージョンを集計しましたstd::iostream

編集:Looks likes GManの答えが良いです。彼はstd::endlも働きます!

+0

私はこの答えをサポートします:P – GManNickG

+0

実際にはありません。私の記事からリンクされた記事を読もうと思えば、明示的に実装したものだけでなく、すべてのファンクタを動作させる方法を知っているはずです。 – EFraim

31

問題は、std::endlが関数テンプレートで、演算子として<< であることです。だから、あなたが書くとき:

my_stream << endl; 

あなたはオペレータ のためだけでなく、endlためのテンプレートパラメータを推定するようにコンパイラを気に入るだろう。これは不可能です。

したがって、マニピュレータで作業する<<〜 の追加の非テンプレートオーバーロードを記述する必要があります。彼らのプロトタイプは次のようになります。

UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&)); 

(2つの他の人はあなたがすべての マニピュレータを許可したい場合は、あなたが提供することも必要がありstd::basic_ios<char>によってstd::ostreamstd::ios_baseを、交換がある)、その実装はと非常に似ていますあなたのテンプレート のいずれか。実際には、あなたがこのような 実装のためのテンプレートを使用することができるように似て:

typedef std::ostream& (*ostream_manipulator)(std::ostream&); 
UIStream& operator<<(UIStream& os, ostream_manipulator pf) 
{ 
    return operator<< <ostream_manipulator> (os, pf); 
} 

最後の注意、多くの場合、カスタムstreambufを書くことは、多くの場合、1はテクニックにあなたを適用達成しようとするものを達成 に良い方法です使っている。

+2

+1これは私が昨日提供したのと同じ回答です。不運にも無視されています。 http://stackoverflow.com/questions/1133739/how-does-ofstream-or-ostream-type-cast-all-types-to-string/1134501#1134501 –

+0

実際に私は同じ解決策を見つけましたが、関数本体: 'pf(* this); return * this; '、しかし、私は' op << 'を、派生したostreamerクラスのメンバーとして追加します。 – TrueY

4

私はここに、私の問題を解決するためにこれをしなかったが、私のコードの一部です:

template<typename T> 
    CFileLogger &operator <<(const T value) 
    { 
     (*this).logFile << value; 
     return *this; 
    } 
    CFileLogger &operator <<(std::ostream& (*os)(std::ostream&)) 
    { 
     (*this).logFile << os; 
     return *this; 
    } 

MAIN.CPP

int main(){ 

    CFileLogger log();  
    log << "[WARNINGS] " << 10 << std::endl; 
    log << "[ERRORS] " << 2 << std::endl; 
    ... 
} 

私はここhttp://www.cplusplus.com/forum/general/49590/

ホープの参照を得ましたこれは誰かを助けることができます。 C++ 11と

受け入れ答えに加えて
0

、タイプのoperator<<をオーバーロードすることが可能である:

decltype(std::endl<char, std::char_traits<char>>) 
関連する問題