C#でC++のstd::coutの真似をしてみた
研究で分子動力学シミュレーションをするためにC++で書いているのですが、C#、ActionScript、Rubyなどの言語は触ってきた自分でも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#!
実行すると
と出力されます。しつこかったですね、ごめんなさい。
シフト演算子<<で実現(失敗?)
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++に負けた気がする。。。