読者です 読者をやめる 読者になる 読者になる

C++0x が底辺 C++er にもたらすメリット

C++

 開発環境が C++ から C++0x に移行することで多くの利益がありますよね。そういうものについて C++er が多くの記事を書いてくれたりしているわけです。
 しかしエキスパートの方々の鋭い記事を精査する前にそもそも現行の C++ だってろくに使ってねーよ、的な人はたくさんいると思うのです。かくいう僕もその一人なんですが、だからといって C++0x を「C に毛が生えた言語」として使うにはあまりにもったいないというか、給料貰うのが申し訳なくなってきます。そこで、底辺 C++er が C++0x 環境で開発することで嬉しくなるポイントをいくつか紹介しようと思います。

■constexpr
 C++ では、コンパイル時定数の表現能力が高くありませんでした。例えばこんなん。

// C++
int pow2( int v ) { return v * v; }

int main()
{
    switch( foo() ) {
    case pow2( 2 ): break; // コンパイルエラー
    }
}

C++ では case にはコンパイル時に決定できる定数しか与えられないので、関数呼んだ結果を case に使えないです。しかしこんなん、見たら分かるやんか!ということでたいへんもどかしかったわけですがこれが解消されます。

// C++0x
constexpr int pow2( int v ) { return v * v; }

int main()
{
    switch( foo() ) {
    case pow2( 2 ): break; // ok
    }
}

switch ~ case が実行時の計算に対応しているのではありません。constexpr を使うことで、コンパイル時に計算できるものなら力ずくで計算してくれるようになるのです。もちろん pow2 は普通の関数として実行時に呼び出す事もできます。これで、コンパイルを通すためだけに同じ式を何度も書かなくてよくなりますね。

■auto
 C++0x では auto を書きまくることになると思われます。例えばこんなん。

// C++0x
vector< int > get_values()
{
    vector< int > v = { 1, 2, 3, 4 };
    return v;
}
int main()
{
    auto v = get_values();
    for( auto i = v.begin(); i != v.end(); ++ i ) {
        cout << * i << endl;
    }
}

 main 関数では、型名がきれいサッパリ無くなりますね。そんなバカな、という感じですが、 get_values(), v.begin() それぞれ関数の戻り値の型がコンパイル時に分かってるわけなので、v, i それぞれの型が何であるかをコンパイラが自動補完してくれるのです。長い型名に翻弄されることもずいぶんと減るはずです。

■decltype

// C++
int a;
int a_old;

例えば、変数 a があって、その前回値を記憶する変数 a_old が必要だったとします。このとき、設計変更で a の型が int から double に変更になったとします。もしかしたら a_old の型を修正し忘れるかもしれません。そもそもこのコードでは、型を2重管理しちゃってるわけです。こういうとき、C++0x では decltype という構文が使えます。

// C++0x
int a;
decltype( a ) a_old;

「a_old の型は a と同じ型ですよ」と明示的に書けるのですね〜。


■右辺値参照
 神。ちょっと考え方が難しいのですが、この概念だけは頑張って Web を漁って理解しておきましょう。

// C++
class person
{
public:
    person( string const & name ) : name_( name ) {}
    string name_;
};
int main() { person a( "kura" ); }

このとき、string は 2 度生成されますね。
まずコンストラクタ引数に渡すのにひとつ。次に person::name_ でひとつ。string って内部にバッファを持ってますので、バッファが 2 個作られているわけです。文字列を 1 個渡すだけだというのにバカバカしいですね。
しかし C++ ではこれを避けられませんでした。そこで右辺値参照の登場です。バッファを作る回数を 1 回にします。

// C++0x
class person
{
public:
    person( string const & name ) : name_( name ) {}
    person( string && name ) : name_( move( name ) ) {} // 追加
    string name_;
};
int main() { person a( "kura" ); }

とまぁ、こんな感じで 1 行足してやればバッファは 1 度しか作られなくなります。