C++11とか

気がつくと、C++が随分様変わりしてました。いえ、未だに旧態依然とした所も沢山残っていますけれど、オブジェクト指向言語として、随分頑張っているじゃないか、ってそう思います。

尤も、このC++11をフルにサポートしている処理系がどのくらいあるのかよくわかりませんけれど。G++でさえ、まだ、実装されていない機能もあるようなので。

様々な機能が追加されたり仕様が変更されたりしていますが、プログラムの可読性を上げるという意味では、ラムダ式が実装されたのは大きいでしょう。汎用性の高いSTLやBOOSTなどのライブラリや、GUIのウィジェットなんかは、コールバック関数に、その動作を記述することが多いので、呼び出しコードと、コールバックとが同一の場所に記述できるのは、非常に強力だと思います。

ラムダ式自体は、LispやPrologなどの、データとコードの区別がない言語や、Ruby, Python, ActionScript そして Javaなどで既に広く用いられていますが、C++でもそういったスタイルのコーディングができるようになったと言うことです。

例えば、リストの中から、特定の条件にマッチするものを探す処理を記述する場合、Rubyを使うと次のように書けます。

v = Array.new
ret = v.find_all {|item|
    item % 4 == 0
}

C++11で同様の処理を実装するには、

std::vector<int> ret;
std::vector<int>::iterator iter = v.begin();
while ((iter = std::find_if(iter, v.end(), [=](int item)
        {
          return item % 4 == 0;
        }
)) != v.end())
{
  ret.push_back(*iter++);
}

と、まあ、やや冗長にはなりますが、それでも、検索機能、find_if()の呼び出しと、マッチする条件を記述した関数とが、同じ場所に書かれているので、あちこちから切り貼りして持ってこないでも済みましたし、何より、コードを読む、維持する、変更する、ということを考えた時に、ココを見れば全ての動作が判るというのは、非常にすばらしいことです。

マッチ処理をする関数は別の場所に関数として宣言しておいて、ここには適切なコメントを置いておけば十分だという考え方もあるでしょう。実際、C++03まではC++ではそうするしかなかったわけです。が、マッチする関数の挙動を変更した時に、呼び出し元に書かれたコメントまできちんと修正して回るでしょうか?

修正されなかったコメントは、バグの温床になってしまいます。挙動が変わっているのに、コメントには古い動作が書かれていたら、動作がおかしいのが、どこなのか、仮に関数の挙動が違うことが判っても、それが、関数のバグなのか、或いは呼び出し元たるこちら側を直すべきなのか、判断が難しい場合も出てくるでしょう。コメントよりも、コードそのものがそこに一緒にあることの方が余程、わかりやすいというものです。

しかし、こうしてみると、STLやBOOSTの多機能さも相俟って、最早、C++のソースって、Cの頃から比べると、全く別物。Javaなんかとかなり区別がつきにくくなってきてますね。まあ、Javaの文法がCの系譜から多くの影響を受けている部分もあるのでしょうけれど。