10

独自のロギング クラスを作成し、それをストリームとして使用しようとしています。

logger L;
L << "whatever" << std::endl;

これは私が始めたコードです:

#include <iostream>

using namespace std;


class logger{
public:
    template <typename T>
    friend logger& operator <<(logger& log, const T& value);
};

template <typename T>
logger& operator <<(logger& log, T const & value) {
    // Here I'd output the values to a file and stdout, etc.
    cout << value;
    return log;
}

int main(int argc, char *argv[])
{
    logger L;
    L << "hello" << '\n' ; // This works
    L << "bye" << "alo" << endl; // This doesn't work
    return 0;
}

しかし、コンパイルしようとすると、operator<< (std::endl を使用する場合) の定義がないというエラーが発生しました。

pruebaLog.cpp:31: error: no match for ‘operator<<’ in ‘operator<< [with T = char [4]](((logger&)((logger*)operator<< [with T = char [4]](((logger&)(& L)), ((const char (&)[4])"bye")))), ((const char (&)[4])"alo")) << std::endl’

だから、私はこの種のストリームを受け入れるために operator<< をオーバーロードしようとしましたが、それは私を怒らせています。やり方がわかりません。たとえば、ostream ヘッダー ファイルの std::endl の定義を調べて、このヘッダーを使用して関数を作成しました。

logger& operator <<(logger& log, const basic_ostream<char,char_traits<char> >& (*s)(basic_ostream<char,char_traits<char> >&))

しかし、運がありません。char を直接使用する代わりに、テンプレートを使用して同じことを試しました。また、単純に「const ostream& os」を使用してみましたが、何も試しませんでした。

私を悩ませているもう1つのことは、エラー出力で、operator<<の最初の引数が変更されることです。ポインターへの参照である場合もあれば、二重参照のように見える場合もあります...

4

4 に答える 4

9

endl奇妙な獣です。定数値ではありません。それは実際には、何よりも関数です。次のアプリケーションを処理するには、特別なオーバーライドが必要ですendl

logger& operator<< (logger& log, ostream& (*pf) (ostream&))
{
  cout << pf;
  return log;
}

これは、参照を受け取り、ostream参照を返す関数の挿入を受け入れostreamます。それが何endlです。

編集:「コンパイラがこれを自動的に推測できないのはなぜですか?」というFranticPedanticの興味深い質問に応えて。その理由は、さらに深く掘り下げると、endl実際にはそれ自体がテンプレート関数であるためです。それは次のように定義されます:

template <class charT, class traits>
  basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );

つまり、あらゆる種類のostream入力と出力を受け取ることができます。したがって、問題は、コンパイラがそれが関数ポインタである可能性があると推測できないことではなく、あなたが渡すつもりだったものT const &を理解できないことです。質問で提示されたテンプレートバージョンは、任意の関数へのポインタを受け入れます2番目の引数として、しかし同時に、テンプレートは潜在的な関数の無限のセットを表すため、コンパイラーはそこで意味のあることを何もできません。 endloperator<<endl

operator<<2番目の引数がテンプレートの特定のインスタンス化と一致する特別なオーバーロードを提供すると、呼び出しを解決できます。endl

于 2010-05-10T14:42:14.143 に答える
5

endlはIOマニピュレータです。これは、参照によってストリームを受け取り、そのストリームに対して何らかの操作を実行し、そのストリームを参照によって返すファンクタです。cout << endlは、と同等ですcout << '\n' << flush。ここflushで、は出力バッファをフラッシュするマニピュレータです。

クラスでは、この演算子のオーバーロードを作成する必要があります。

logger& operator<<(logger&(*function)(logger&)) {
    return function(*this);
}

logger&(*)(logger&)参照によってを受け入れて返す関数のタイプはどこにありますかlogger。独自のマニピュレータを作成するには、そのシグネチャに一致する関数を作成し、ストリームに対して何らかの操作を実行させるだけです。

logger& newline(logger& L) {
    return L << '\n';
}
于 2010-05-10T14:40:13.587 に答える
0

C ++では、基盤となるI/Oメカニズムをカプセル化するのはストリームバッファです。ストリーム自体は、文字列への変換とI/O方向のみをカプセル化します。

したがって、独自のストリームクラスを作成するのではなく、事前定義されたストリームクラスの1つを使用する必要があります。I / Oに移動させたい新しいターゲット(システムログなど)がある場合、作成する必要があるのは、独自のストリームバッファー(から派生std::streambuf)です。

于 2010-05-10T14:39:49.707 に答える
0

問題は、この回答に示されoperator<<ているのと同じタイプの関数を受け入れるためにストリームがオーバーロードされていないことだと思います: std::endl is of unknown type when overloading operator<<std::endl

于 2010-05-10T14:44:08.013 に答える