Boost.Variant そのいち

本格的に boost を触る前に、というかおれの触りたい Boost.Spirit が data structure として Boost.Variant を前提ぽい感じで使ってて document にも「わかっとけ」的なことが書いてあったのでまずは Boost.Variant から。

とはいうものの多分使うだけなら http://www.boost.org/doc/libs/1_44_0/doc/html/variant/tutorial.html を手を動かしながら読めばいいくらいで。そんなに量も多くないので boost document に慣れるのにもいいかも。

で、これが何かというと、

  • 複数の型をひとつの型に integrate できる
  • それぞれの型に対する access をきめ細かく書ける

というのがまぁ妥当な気がする。

日本語の resource ではよく型安全な union と書かれてたりするんだけど union てのはある memory 上の data を複数の型として認識できるという機構なので全然ちがうもの。

Boost.Variant ではたとえば int 型と char 型をいっしょくたにしたとして int 型の値を代入したあとでは char 型の値を代入するまで char 型として値に access できない。あと POD 型じゃなくても integrate できるという特性がある、というか union が POD 型しか同じように扱えない、ということなんだけど。

つまり union では以下のようなことが可能だけど、

#include <iostream>

union test_type {
    int n;
    char c;
};

int main(void) {
    test_type t;
    t.n = 4;

    std::cout
        << t.n << "\n"  // print as a int
        << t.c << "\n"  // print as a char
        << std::endl;

    return 0;
}

Boost.Variant では以下はできない。

#include <iostream>
#include <boost/variant.hpp>

int main(void) {
    boost::variant<int, char> v;
    v = 1;      // assign the value of the type "int"

    std::cout
        << boost::get<int>(v)
        << boost::get<char>(v)  // this expression causes error!
        << std::endl;

    return 0;
}

あとどんな値でも扱える Boost.Any との比較もあるんだけどこれは面倒なので公式の document から引っ張ってきてしまおう。超訳なので注意。なんでこんなうさんくさい語調なのかというとおれの読んだ部分の boost の document のノリが全般的にこういう感じだから。

Boost.Variant と Boost.Any の違い

union コンテナーとの差別化として、 Variant ライブラリは Any ライブラリと多くの類似点を持っているんだ。だけどどちらももう片方の機能を完全に包含しているわけではないから、ひとつのライブラリだけを全般的に使うのはオススメできないね。

さて、 Boost.Variant は Boost.Any に比べていくつか優れた点があるんだ。

  • Boost.Variant はその内容の型がユーザーが指定した有限個の型のうちのひとつであることを保証するよ。
  • Boost.Variant はコンパイル時に visitor パターンの適用に対して型チェックが行われるよ ( 訳注: たぶん誤訳。原文は provides compile-time checked visitation ) 。 ( 反対に、現在の Boost.Any は visitor パターンに対して型チェックはしないんだ。でももし使えたとしても、実行時チェックが必要だね。 )
  • Boost.Variant は内容に対してジェネリックな visitor パターンが使えるんだ。 ( Boost.Any でも visitor パターンは使えるけど、明示的に指定した型だけなんだよ。 )
  • Boost.Variant はスタックに構築されるから効率的だよ ( 動的にメモリ確保しないんだ ) 。

もちろん Boost.Any にも Boost.Variant より優れたところがあるよ。

  • Boost.Any は名前の通り、その内容はどんな型でもよくて、素晴らしい柔軟性を持っているよ。
  • Boost.Any はスワップ操作の際に例外を投げないという保証があるんだ。
  • Boost.Any は template によるメタプログラミング技法をちょっとしか使っていないよ。 ( 結果的にわけのわからないエラーメッセージが少なくなるしコンパイル時の処理やメモリ必要量が減るんだ ) 。
Miscellaneous Notes - 1.44.0

とりあえずこんなもんかな。つぎは実際に触ってみようという方向で。