C#でC++のstd::coutの真似をしてみた

研究で分子動力学シミュレーションをするためにC++で書いているのですが、C#ActionScriptRubyなどの言語は触ってきた自分でもC++とは越えられない壁を感じています。最近は宣言と実装を分ける方法がやっとわかったばかりです。。。


ところで、C++には

cout << "Hello World!" << endl;

というように、<<を続けることで同じ動作(この場合はコンソール出力)を実行する文法があるのですが、C#では見たことが無いような気がします。そこでちょっとお遊びで書いてみました。

関数で実現

関数に関数を返させるという方法でまずは書いてみました

const string endl = "\n";
static SelfReturn<string> cout(string str)
{
    Console.Write(str);
    return cout;
}
delegate SelfReturn<T> SelfReturn<T>(T obj);

として

cout("Hello World!")(endl)("Hello World!")(endl)("Hello World!")(endl);

と実行します。
delegateで自己言及ができるか不安でしたが、ちゃんとコンパイル通りました。さすがはC#
実行すると

Hello World!
Hello World!
Hello World!

と出力されます。しつこかったですね、ごめんなさい。

シフト演算子<<で実現(失敗?)

C++は<<を使っているので、真似てみようと思いました。
coutのシングルトンクラスを作り、演算子を定義してます。

public class CoutSingleton
{
	private static CoutSingleton cout_ = null;
	public static CoutSingleton Instance
	{
		get
		{
			if (cout_ == null)
			{
				cout_ = new CoutSingleton();
			}
			return cout_;
		}
	}
	private CoutSingleton() { }

	public static CoutSingleton operator <<(CoutSingleton cout, string str)
	{
		Console.Write(str);
		return cout;
	}
}

しかし

オーバーロードされた shift 演算子の最初のオペランドはそれを含む型と同じ型、2 番目のオペランドの型は int でなければなりません

と怒られてしまいました。なので、シフト演算子を諦めて、他の演算子にしてみました。
しかし、いざ

CoutSingleton cout = CoutSingleton.Instance;
cout <= "Hello World!" <= endl;

と書くと

割り当て、呼び出し、インクリメント、デクリメント、および新しいオブジェクトの式のみがステートメントとして使用できます。

と怒られてしまいました。あぁそっか命令文として解釈されないのね。。。ありゃりゃ…

妥協して、Writeメソッドを作る

public class CoutSingleton
{
	private static CoutSingleton cout_ = null;
	public static CoutSingleton Instance
	{
		get
		{
			if (cout_ == null)
			{
				cout_ = new CoutSingleton();
			}
			return cout_;
		}
	}
	private CoutSingleton() { }
	public CoutSingleton Write(string str)
	{
		Console.Write(str);
		return this;
	}
}

そして

CoutSingleton cout = CoutSingleton.Instance;
string endl = "\n";
cout.Write("Hello  World!").Write(endl).Write("Hello  World!").Write(endl).Write("Hello  World!").Write(endl);

として、

Hello World!
Hello World!
Hello World!

と出ました。

うーん。。C++に負けた気がする。。。