私は、C++0xのすべてに賛同しているわけではない。むしろ逆に、不満は多い。オレの欲しかったこの機能がないという不満ではない。こんな機能いらないだろという不満である。
ユーザー定義リテラル
ユーザー定義リテラルは、無駄である。識別子はかならずアンダースコアから始まらなければならない。これは、とても危険だ。なぜ、予約語の制限を無視できるかというと、ユーザー定義リテラルの識別子は、エンティティではない。すなわち、名前ではないからだ。名前ではないゆえに、予約語の制限にはあてはまらない。
ましてや、ユーザー定義リテラルを、名前空間の中に入れることができないというのは、致命的だ。もちろん、名前空間の中でも定義できるが、おそらく、実用にならないだろう。
それに、ユーザー定義リテラルでなければできないことというものがない。では、単なるシンタックスシュガーか。
// ユーザー定義リテラル auto x = "hogehoge"_hoge ; // 関数 auto y = hoge("hogehoge") ; // クラスへのキャスト auto z = hoge("hogehoge") ;
この砂糖は、果たして既存のクラスやキャストより甘いのであろうか。関数やキャストで十分ではないか。
これに対して、「おいおい江添、バカだなぁ。お前まだ、テンプレートメタプログラミングを知らないのか。ユーザー定義リテラルを使えば、整数の引数が、テンプレート実引数になるじゃないか」という意見がある。それは、承知している。連中の言い分はこうだ。
template < char ... args > struct placeholder {} ; template < char ... args > placeholder< args... > operator "" _ (){ return placeholder< args... >() ; } int main() { 1_ ;// placeholder<'1'> 2_ ;// placeholder<'2'> 123_ ;// placeholder<'1', '2', '3'> }
ご覧のように、リテラル演算子テンプレート(literal operator template)の場合、実引数ではなく、テンプレート実引数に、リテラルの文字列が、一文字づつ渡される。これをつかえば、std::bindに使われる、std::placeholders::_1のような、汚い実装は必要ないではないかということである。
しかし、本当にこんなコードを書きたいだろうか。私は御免だ。このコードを書くには、Variadic Templatesとユーザー定義リテラルに、相当精通していなければならない。そもそもこれは、ユーザー定義リテラル本来の用途ではない。たまたま、こういう事にも使えるというだけだ。メタプログラミングに使いたいのならば、最初からメタプログラミング目的の機能を設計すべきだ。
long long int
long long intは、C99から輸入したものである。C畑の連中の考えることは、たいていクソである。これも例外ではない。long long intは、明確に規定していないものの、limit.hの定義を考えれば、少なくとも64bit以上の整数である。
じゃあ、将来、128bit以上を保証する整数が欲しくなったらどうするのか。long long long intを付け加えるのだろうか。では256bitは如何。子供の考えた必殺技じゃあるまいし、バカバカしい。
初期化リスト
これまで、構造体や配列は、特別な初期化の文法を使うことが出来た。
int x[3] = {1, 2, 3} ;
初期化リストは、これを、ユーザー定義のクラスにも、使えるようにしたものだ。
std::vector<int> x = {1, 2, 3} ;
なるほど、確かに教科書の例文を書く際には、分かりやすい。多分、初心者受けもいいだろう。これは、一見して、良い機能に見える。
しかし、ソースコードにデータを直接記述して初期化するような決め打ちの泥臭い処理が、そんなに頻繁に使われるだろうか。配列や構造体は、コンパイル時に初期化の方法を伝えられるという利点がある。現実のCのコードでも、テーブルの構築などにも使われている。しかし、ユーザー定義のクラスは、そのような簡単な、ビットワイズな初期化をすることはできない。
もちろん、シンタックスシュガーは重要だ。しかし、現実には、ファイルを読み込むだとか入力を受け付けるなどしなければ、初期化ができない場合がある。これは、結局、実行時まで、初期化ができないことを意味する。
もちろん、初期化リストに使えるのは、リテラルだけではない。
void f( int x, int y, int z ) { std::vector<int> x = {x, y, z} ; }
しかし、要素数も、実行時に得られる情報に依存しているならば、結局、初期化リストを使うことはできない。
std::vector<int> v ; while( int value = get_runtime_input_somehow() ) { v.push_back(value) ; }
とはいっても、初期化リストは、まだそれなりに使い道はあるだろう。それほど便利ではないというだけの話だ。結局、C++の思想である、組み込み型とユーザー定義型を、完全に同じ文法で扱えるべきだという思いが、影響しているものと思われる。
std::bind
不要。lambdaを使うべき。
1 comment:
ソースコードは人間が書くものとは
限らないので、ソースコードを
プログラムから自動生成する際に
データを初期化リストに突っ込むのは、
珍しいことではないでしょう
自分は経験ないのですが、
ファイルシステムが
ないような環境で動作させるには、
ソースコードにデータを書くのが簡単なので、
初期化リストは有効なのかも
Post a Comment