テンプレート引数にstd::endlを渡す

解決


ペン  2007-11-03 06:39:28  No: 66731

以下のようなDebugクラスを作成したのですが、
Debug::operator<<にstd::endlを渡すとコンパイルエラーになります。
どのように修正したらよいでしょうか? 

#include <iostream>
using namespace std;

class Debug {
public:
  template <class T>
  Debug& operator<<(const T& a) {
    // デバッグ時のみ std::cout << a を実行する
    std::cout << a;
  }
};

int main() {
  Debug d;
  d << "foo" << 100 << '\n'; // 問題なし
  d << std::endl; // コンパイルエラー
}

コンパイルエラーメッセージ:
no match for 'operator<<' in 'd << std::endl'

g++ 3.4.4 cygwin


ペン  2007-11-03 06:44:38  No: 66732

あれ、Debug::operator<<で戻り値を返していないのにコンパイルできた…。
(-Wallをつけてコンパイルしたら警告がでた…)

すみません。以下のように修正します。

#include <iostream>

class Debug {
public:
  template <class T>
  Debug& operator<<(const T& a) {
    std::cout << a;
    return *this;  // ここを修正
  }
};

int main() {
  Debug d;
  d << "foo" << 100 << '\n'; // 問題なし
//  d << std::endl; // コンパイルエラー
}


yoh2  2007-11-03 08:29:45  No: 66733

std::endlが単なる関数ではなく、関数テンプレートだからです。
std::endlのプロトタイプは

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

となっています。(名前空間stdは省略)
単純に

template<class T> Debug& Debug::operator<<(const T& a)

にstd::endlを渡しただけでは、charTとtaritsを推論できないので
コンパイルエラーになります。

template<class T> Debug& Debug::operator<<(std::ostream& (*pf)(std::ostream &))
{
    std::cout << pf;
    return *this;
}

というoperator<<を定義すればstd::endlやその他各種マニピュレータが
とりあえず使えるようになります。(よい解かどうかは別として)

もし、Debugの用途がデバッグ出力用のクラスだとしたら、Debugを
std::ostreamから派生させて、さらに低レベル出力用クラスとして
std::streambufの派生クラスを定義するとか。
て、大掛りすぎるか……


yoh2  2007-11-03 08:31:42  No: 66734

間違い訂正。
> template<class T> Debug& Debug::operator<<(std::ostream& (*pf)(std::ostream &))

これ、テンプレート関数にする必要はありません (Tの使いどころなし)。
正しくは

Debug& Debug::operator<<(std::ostream& (*pf)(std::ostream &))

です。


ペン  2007-11-03 21:44:19  No: 66735

yoh2さん、ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加