C++ から学んだいくつかのどうでもいいこと

C++ Advent Calendar に参加してみました。
どうせ C++ の頭おかしい人達がいっぱい集まってるので、そっち方面はその辺の人に任せるとして、何かこう曖昧な話をだらだらと書いてみます。

コーディング規約について

コーディング規約は、言語のコードをある特定の方向へと誘導することができます。まあこの特定の方向の先にあるのがひどいプロジェクトの成功だといいのですが、よくとんでもない方向へと突き進んでいることがあります。
何でそうなるのかって考えると、どの方向へ進もうとしているのかというのが明確にされていないということなんじゃないかと思うわけです。つまり、何を目的としてこのコーディング規約は作られたのか、誰に対してのコーディング規約なのかということです。
特定のプロジェクトを成功へ導くために作られたのか、多くのよくありそうなプロジェクトのためのひな形として作られたのか、バカ除けのために作られたのか、はたまたプログラマへ無駄な抑圧を掛けるために作られたのか。
時々、独りよがりなコーディング規約の話とか聞きますが、それって大抵『俺が読めるコードを書け』ってだけだったりします。まあ確かに Boost.PP や Boost.MPL を多用したコードとか見ると制限したくなるのも分からなくは無いですが、それによってプロジェクトが死ぬ場合だってある(もちろん制限しないことでプロジェクトが死ぬ場合もある)わけで、そこら辺をちゃんと考えた上で作って欲しいところですね。
あと特定のコーディング規約、例えばGoogleC++スタイルガイドとかを使うのもありだとは思いますが、それはGoogleのプロジェクトの方向と、自分のプロジェクトの方向がほぼ似通っている場合に限ります。new 使ったら 100 万人ぐらい死ぬようなプロジェクトで『shared_ptr 使いましょう』なんて言ってたらいろいろ終わります。
ということで、自分でコーディング規約を作る際も、どこかのコーディング規約を引っ張ってくる際も、ちゃんとやりたいことが果たせるのかどうかというのを考えましょう。


まあそもそも自分はコーディング規約にあまり価値を見出してなくて、「おまえら俺のコードを見て学習しろ!俺もおまえらのコードを見て学習させてもらうから!」という考えなので、基本的なスタンスは「読めない方が悪い」です。
そんなこと言うと、IOCCC みたいなコードを挙げる人がいたりするのですが、書く人は自分がわざと読めなくなるようなコードを書いているはずがないので、そんなコードはまず無いということにしておきます。もし、IOCCC みたいなコードが本当にその本人が読みやすいと思って書いているのであれば、自分は頑張って読むことにします。いややっぱり読まないです。

コーディング規約と言語の違い

さっき自分はコーディング規約に価値を見出してないって言いましたけれども、コーディング規約と言語って使う側にとって何が違うんでしょうね。
言語機能として入っていないのも、コーディング規約によって制限されているのも、どちらも使えないっていう点では同じです。
言語機能として入っていないのはコンパイル時にチェックできるけれども、コーディング規約は人間がチェックしないといけないような曖昧な部分が多いぐらいでしょうか。
まあつまり何が言いたいかっていうと、もし変なコーディング規約があったとしても「これはC++じゃなくて俺の上司が脳内で考えた上C言語なんだ」と暗示することで、C++の機能が使えなくてイライラしたあげくにビット演算をゴリゴリ書いた上で「コーディング規約に禁止だとは書かれていません。それにこれは C のコードですよ。あなた C++ だけじゃなくて C のコードも読めないんですか?」とか言ってビット演算もコーディング規約で禁止されて憎しみが連鎖してしまうみたいなことは無くなるかもしれません。

演算子オーバーロードについて

演算子オーバーロードは、一般的には「本当に演算子オーバーロードを使うのが正しいと確信している場合を除いて使ってはならない」というガイドラインがあると思います。知らなかった人は今覚えてください。
で、これをこのままコーディング規約に含めると、『誰が』正しいと確信すれば使っていいのかという問題が残ります。
さっきも書いたように、自分は「読めない方が悪い」というスタンスなので、『書いた本人が』正しいと確信しているのであれば、別にいいんじゃないかなと思っています。これは「分かりやすい関数名を書け」っていうのも同じですね。『書いた本人が』分かりやすいと思っているのであれば構わないと思っています。
もし一人の結論がダメな世界なら、関連する人全員で徹底的にレビューして、最終的な結果が得られるまで議論すればいいです。多分そっちの方が楽しいです。まあその辺どうするかは、関わる人数に応じて適当にやればいいんじゃないですかね。
まあつまり『誰が』というのは、その世界に合うように適当にうまく折り合いを付けましょうってことです。

シンタックスシュガーについて

シンタックスシュガー(syntax sugar とか書くといろんな場所から突っ込まれます)は、出来ることが増える訳じゃないからそんなに重要じゃないって話を聞くことがあります。
多分そんな人からすれば、

vector<hoge>::const_iterator it =
    find_if(v.begin(), v.end(), [](const hoge& h) { h.a == 10; });
if (it != v.end()) {
    do_something();
}

for (int i = 0; i < v.size(); i++) {
    if (v[i].a == 10) {
        do_something();
        break;
    }
}

は同じものに見えるはずです。単純な機能しか使っていない分、後者の方が好ましいって人もいるかもしれません。
プログラミングは意味を紡ぐ作業なので、プログラマは出来る限りその意図を伝えるべきです。ということで前者のコードの方が意図が伝わりやすい分優秀です。
まあコードだけで伝えられるものには、今のところは(人間的にも言語的にも)限界があるので、最後にはコメントに頼ることになるでしょうけど(ちなみに自分でコメントを付ける際の基準は『コードだけで自分の意図が伝わると思うかどうか』です。この辺で付けるかどうかの判断も演算子オーバーロードの『誰が』って話と同じですね)。


ところで、これは C++03 だと

struct pred {
    int value;
    pred(int value) : value(value) { }
    bool operator()(const hoge& h) const {
        return h.a == value;
    }
};
...
vector<hoge>::const_iterator it =
    find_if(v.begin(), v.end(), pred(10));
if (it != v.end()) {
    do_something();
}

とか書くことになって、これが大変面倒なので、自分はいつも for 文回してます。はい、さっきから偉そうなことを言っておいて毎回意図の伝わりにくいコードを書いています。だって面倒ですから。面倒さはプログラムの質を変えるのです。