boost::variant

トップページ > 拡張データ型 >

abstract

必要なヘッダ
<boost/variant.hpp>
出来ること
指定した型リストに属する値を格納できる、安全Union
リファレンス
en

sample

#include <iostream>
#include <string>
#include <boost/variant.hpp>
using namespace std;

// 「2倍する」Visitor
struct do_double : boost::static_visitor<void>
{
	template<typename T>
	  void operator()( T& t ) const { t = t + t; }
};

int main()
{
	boost::variant<int,double,string> v;
	v = -2;
	assert( v.which() == 0 );           // 中身がintなことを確認
	cout << boost::get<int>(v) << endl; // intを取り出し

	v = 3.14;
	assert( v.which() == 1 ); // 中身がdoubleなことを確認
	cout << v << endl;        // 実は表示だけならget<...>は要らない

	v = "hoge";
	assert( v.which() == 2 );        // 中身がstringなことを確認
	apply_visitor( do_double(), v ); // Visitorを投げる
	cout << v << endl;

	return 0;
}

出力例

-2
3.14
hogehoge

etc

C++言語のunionと同じように、複数の型の変数を同じ領域に持てるようにするものです。 上の例だと、「intかdoubleかstringのどれかが入っている変数」vを使っています。 unionとの違いは、コンストラクタの必要なオブジェクトも格納できること (unionには例えばstd::stringは入れられません) と、which() メンバ関数のように、 中身に今何が入っているのかを判定する手段が用意されていること。 any の型制限版と考えても良いかも。

あと、Variantは実体の型が実行時に動的に変わる一種の多態と考えられることから、 Visitorパターン にのっとった操作ができるようになっていて、かなり便利です。

特殊な記法が必要ですが、再帰的なvariantも書けます。 下の例は、葉にintが来る二分木を定義しています。

typedef make_recursive_variant<
  int, pair<recursive_variant_, recursive_variant_>
>::type binary_tree;

// binary_tree ≒ variant<,int,pair<binary_tree,binary_tree>>

presented by k.inaba (kiki .a.t. kmonos.net) under CC0