演算子をオーバーロードしました<<
template <Typename T>
UIStream& operator<<(const T);
UIStream my_stream;
my_stream << 10 << " heads";
動作しますが:
my_stream << endl;
コンパイルエラーが発生します:
エラーC2678:バイナリ '<<':タイプ 'UIStream'の左側のオペランドを取る演算子が見つかりません(または許容できる変換がありません)
my_stream << endl
を機能させるための回避策は何ですか?
std::endl
は関数であり、std::cout
はoperator<<
を実装することによってそれを利用し、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;
}
うまくいけば、これはこれらのものがどのように機能するかについてより良い考えをあなたに与えるでしょう。
問題は、演算子std::endl
と同様に、<<
が関数テンプレートであることです。だからあなたが書くとき:
my_stream << endl;
コンパイラーは、演算子とendl
のテンプレートパラメーターを推定する必要があります。これは不可能です。
そのため、マニピュレータを操作するには、追加のテンプレートではない、演算子<<
のオーバーロードを記述する必要があります。プロトタイプは次のようになります。
UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));
(他に2つあり、std::ostream
をstd::basic_ios<char>
とstd::ios_base
で置き換えます。すべてのマニピュレータを許可する場合は、これらも指定する必要があります)およびその実装は、テンプレート。実際、非常によく似ているため、次のような実装にテンプレートを使用できます。
typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
return operator<< <ostream_manipulator> (os, pf);
}
多くの場合、カスタムstreambuf
を作成する最後のメモは、多くの場合、使用しているテクニックへの適用を達成するためのより良い方法です。
私はこれを私の問題を解決するために行いました、これが私のコードの一部です:
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/
これが誰かを助けることを願っています。
IOStreamsを拡張するより良い方法については here を参照してください。 (少し時代遅れであり、VC 6に合わせて調整されているため、塩の粒と一緒に使用する必要があります)
重要なのは、ファンクタを機能させるには(そしてendlは "\ n"を出力し、フラッシュすることがファンクタである)、完全なostreamインターフェイスを実装する必要があるということです。
std
ストリームは、仮想メソッドがないため、サブクラス化するようには設計されていません。そのため、これで行き過ぎることはないと思います。 std :: ostreamを集約して作業を行うこともできます。
endl
を機能させるには、endl
などのマニピュレーターを処理する方法である関数へのポインターを受け取るoperator<<
のバージョンを実装する必要があります。
UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );
または
UStream& UStream::operator<<( UStream& (*f)( UStream& ) );
ここで、std::endl
はstd :: basic_ostreamへの参照を受け取って返す関数であるため、ストリームで直接動作しないため、集約されたstd::endl
のstd::iostream
バージョンを呼び出す独自のバージョンを作成する必要があります。
編集:GManの回答の方が良いようです。彼はstd::endl
も動作します!
受け入れられた回答に加えて、C++ 11では、型のoperator<<
をオーバーロードすることが可能です。
decltype(std::endl<char, std::char_traits<char>>)