boost は STL のように非常に汎用性をもったC++ライブラリ群なので ある。言語の拡張とも言えるほど汎用性があるし、ほとんどが ヘッダファイルだけでできた template なので、コンパイルさえ 通ればどのプラットフォーム上でも使える。すばらしい。
Contents
システムに付属の g++ と違うバージョンのものを使いたいなどの 要望が多々あると思うのでメモ。
次に boost をコンパイルするためのツール:
% cd <boost-dir>/tools/build/jam_src % ./build.sh
UNIX系に根ざした make と違い、bjam は Windows も OK な とても汎用的なツールなのだけれど、boost のコンパイル以外で 使ったことはないし、見たこともないので、/usr/bin とかには インストールしない。:
% cp bin.linux/bjam ../../.. % cd ../../..
システムの g++ は使わないので、bjam にいっぱいオプションを指定しないと いけない。詳しくは、<boost-dir>/more/getting_started.html を参照。:
% ./bjam -sTOOLS=gcc -sGCC_ROOT_DIRECTORY=/usr/local/gcc34 -sGXX=g++-3.4 -sGCC=gcc-3.4 -sHAVE_ICU=0 --prefix=/usr/local/gcc34
てな具合で、かなりオプションを指定しないといけない。できたら 上記のコマンド + "install" で OK。
boost::is_const<T> で、T の型が const か const でないかを判断してくれる。 では問題、このうち is_const で const と判断されるのはどれか?
正解は3。ちょっと予想と違う動きなので注意が必要。 この調子で remove_const も注意して使用すること。
boost::mpl::list や boost::mpl::vector などは、型を追加したり、 削除したりできて非常に便利なのだが、あんまり厳密でない。 例えば [ int, char ] というリストがあって、push_front で float を加え、[ float, int, char ] という型をつくる。 で、その後、pop_front で [ int, char ] という型に戻しても、 それは、もとの型と同じではない。ただし同じリストである。 boost::is_same では違うけれど、boost::mpl::equal では同じなのだ。:
#include <iostream> #include <boost/type_traits.hpp> #include <boost/mpl/list.hpp> #include <boost/mpl/push_front.hpp> #include <boost/mpl/pop_front.hpp> #include <boost/mpl/equal.hpp> int main( int argc, char** argv ) { using namespace boost::mpl; using std::cout; using std::endl; typedef list<int, char> Seq1; // <int,char> typedef push_front<Seq1, float>::type Seq2; // <float,int,char> typedef pop_front<Seq2>::type Seq3; // <int,char> // check the equality as C++ Type cout << (boost::is_same<Seq1, Seq3>::value ? "yes" : "no") << endl; // check the equality as MPL Sequence cout << (equal<Seq1, Seq3>::type::value ? "yes" : "no") << endl; }
上の結果は、:
no yes
になる。
boost::lambda には、_1 とか bind とかが定義されているが、これは Boost.Bind ライブラリの _1 とか bind とかとは違う名前空間で 定義されているものなのでとっても気を付ける。具体的には、
Boost.Bind で ::_1 が定義され、Boost.Lambda で ::boost::lambda::_1 が 定義されているので、"using namespace boost::lambda;" とかいうことを していて、しかも"#incude <boost/bind.hpp> とかしていると _1 は 曖昧、とか怒られてコンパイルが通らない。なので明示的に ::boost::lambda::_1 とかした方が無難かと思われる。
以下は一応 GCC-3.2.2 (RedHat9) で確認済みのコード。
なんだか、簡単になっているのか、複雑になっているのかよくわからない けど、「偶数だったら出力」とか「奇数だったら出力」とかいう 関数オブジェクトを作らずにすんだ。:
#include <iostream> #include <vector> #include <list> #include <algorithm> #include <functional> #include <boost/lambda/lambda.hpp> #include <boost/lambda/if.hpp> #include <boost/lambda/bind.hpp> #include <boost/mem_fn.hpp> #include <boost/bind.hpp> using namespace std; // using namespace boost::lambda; class A { public: A(int n): m_val(n) {} bool isEven() { return m_val % 2 == 0; } void print() { cout << m_val << endl; } private: int m_val; }; int main() { vector<A *> v; v.push_back(new A(5)); v.push_back(new A(4)); v.push_back(new A(3)); v.push_back(new A(2)); v.push_back(new A(1)); cout << "Printing even numbers ..." << endl; for_each(v.begin(), v.end(), ::boost::lambda::if_then( ::boost::lambda::bind(&A::isEven, ::boost::lambda::_1), ::boost::lambda::bind(&A::print, ::boost::lambda::_1) )); cout << "Printing odd numbers ..." << endl; for_each(v.begin(), v.end(), ::boost::lambda::if_then( ! ::boost::lambda::bind(&A::isEven, ::boost::lambda::_1), ::boost::lambda::bind(&A::print, ::boost::lambda::_1) )); }
Boost.Test は単体テストをするのに便利なツールを集めたモジュール。 プログラムにBoostを使っているなら、一緒に使えるので便利。
このモジュールを使って単体テストを行って始めて良さがわかった。
int main(int argc, char** argv) のかわりに、こんな関数を定義する。:
using namespace boost::unit_test; using namespace boost::unit_test_framework; test_suite* init_unit_test_suite(int argc, char** argv) { test_suite* test = BOOST_TEST_SUITE("適当な名前"); test->add(BOOST_TEST_CASE(&test_function_1)); test->add(BOOST_TEST_CASE(&test_function_2)); test->add(BOOST_TEST_CASE(&test_function_3)); return test; }
で、実際にテストを行う関数(test_function_1 ..., test_function_x)は void test_function (void) な関数。
出力先の設定 | unit_test_log.set_stream( std::ostream ) |
出力レベルの設定 | unit_test_log.set_threshold_level( <log_level> ) |