Boost — ほぼ標準C++ライブラリ
Installation
パッケージマネージャで
Homebrew で最新版を簡単にインストールできる。 オプションは適当に:
brew install boost
--layout=tagged
でビルドされるため、
リンクするときは末尾に -mt
が必要になる。
ソースから
- https://www.boost.org/doc/libs/release/more/getting_started/unix-variants.html
- https://www.boost.org/build/
- https://boostjp.github.io/howtobuild.html
-
https://www.boost.org/users/download/ から最新ソースを入手して展開。
wget -O- https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.bz2 | tar xj cd boost_1_67_0/
-
ビルドすべきライブラリを考える
./bootstrap.sh --show-libraries
-
適当なオプションを与えて
bootstrap.sh
を実行:./bootstrap.sh --help ./bootstrap.sh --without-icu --with-libraries=context,filesystem,graph,iostreams,program_options,serialization,system,test
設定が
project-config.jam
に書き出され、b2
がビルドされる。./b2 --help
-
~/user-config.jam
に [ツールセットを定義] (https://www.boost.org/build/doc/html/bbv2/reference/tools.html)。darwin
はMac-gcc用:using gcc : 14 : g++-8 : <compileflags>-fPIC <cxxflags>-std=c++14 ; using darwin : 14 : g++-8 : <compileflags>-fPIC <cxxflags>-std=c++14 ; using clang : 14 : clang++ : <compileflags>-fPIC <cxxflags>-std=c++14 -stdlib=libc++ <linkflags>-stdlib=libc++ ;
gccとclangの両方から使える統一ライブラリを作るのは難しいらしいので、 それぞれのコンパイラで別々にビルドしてインストールする。
-
システム標準zlibをリンクしようとしてエラーになるような場合は、 zlib公式からソースを落として展開し、 [一緒にビルドされるように] (https://www.boost.org/doc/libs/release/libs/iostreams/doc/installation.html)
ZLIB_SOURCE
をフルパス指定する。wget -O- https://zlib.net/zlib-1.2.8.tar.gz | tar xz -C ${HOME}/tmp/build export ZLIB_SOURCE=${HOME}/tmp/build/zlib-1.2.8
-
ツールセットを指定してビルド:
./b2 -j2 toolset=gcc-14 link=static,shared runtime-link=shared threading=multi variant=release --layout=tagged --build-dir=../b2gcc --stagedir=stage/gcc stage ./b2 -j2 toolset=darwin-14 link=static,shared runtime-link=shared threading=multi variant=release --layout=tagged --build-dir=../b2gcc --stagedir=stage/gcc stage ./b2 -j2 toolset=clang-14 link=static,shared runtime-link=shared threading=multi variant=release --layout=tagged --build-dir=../b2clang --stagedir=stage/clang stage
-
prefixを指定してインストール:
./b2 -j2 toolset=gcc-14 link=static,shared runtime-link=shared threading=multi variant=release --layout=tagged --build-dir=../b2gcc --stagedir=stage/gcc --prefix=${HOME}/local install
あるいは手動でインストール:
rsync -auv stage/gcc/ ~/local/boost-gcc rsync -auv stage/clang/ ~/local/boost-clang rsync -auv boost ~/local/include
使うとき
インストールした場所とリンクするライブラリをコンパイラに伝える必要がある。 コマンドを直打ちするなら:
clang++ -I${HOME}/local/include -L${HOME}/local/lib mysource.cpp -lboost_iostreams-mt -o a.out
Makefileの変数でいうと:
CPPFLAGS = -I${HOME}/local/include
LDFLAGS = -L${HOME}/local/lib
LDLIBS = -lboost_iostreams-mt
CMakeでは BOOST_ROOT
にprefixを指定:
cmake -DBOOST_ROOT=${HOME}/local ..
math
https://www.boost.org/doc/libs/release/libs/math/
distribution
https://www.boost.org/doc/libs/release/libs/math/doc/html/dist.html
確率分布に従った乱数生成はC++11から <random>
でサポートされるようになったが、
確率密度関数(PDF)や累積密度関数(CDF)はまだ標準入りしてない。
// #include <boost/math/distributions.hpp>
#include <boost/math/distributions/normal.hpp>
#include <boost/math/distributions/poisson.hpp>
#include <boost/math/distributions/binomial.hpp>
#include <boost/math/distributions/chi_squared.hpp>
namespace bmath = boost::math;
bmath::normal_distribution<> dist(mean, sd);
bmath::mean(dist);
bmath::median(dist);
bmath::standard_deviation(dist);
bmath::pdf(dist, x);
bmath::cdf(dist, x);
bmath::quantile(dist, p);
右側の裾が欲しいときは精度を保つために complement()
を使う。
(Rでいう lower.tail=FALSE
)
// good
bmath::quantile(bmath::complement(dist, p));
// bad
bmath::quantile(dist, 1.0 - p)
// good
bmath::cdf(bmath::complement(dist, x));
// bad
1.0 - bmath::cdf(dist, x);
iostreams
https://www.boost.org/doc/libs/release/libs/iostreams/doc/
要ビルド&リンク -lboost_iostreams-mt
gzip 圧縮と展開
#include <iostream>
#include <string>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
int main() {
namespace bios = boost::iostreams;
{
bios::filtering_ostream ost;
ost.push(bios::gzip_compressor());
ost.push(bios::file_descriptor_sink("hello.txt.gz"));
ost << "Hello world!";
}
{
bios::filtering_istream ist;
ist.push(bios::gzip_decompressor());
ist.push(bios::file_descriptor_source("hello.txt.gz"));
std::string buffer;
std::getline(ist, buffer, '\0');
std::cout << buffer << std::endl;
}
}
- deviceを
push()
した時点でchain completeになるので、 先にfilterをpush()
する必要がある。 コンストラクタにfilterを渡してもよい。 file_descriptor
はfailビットが立つとすぐ例外を投げて “No such file or directory” などを知らせてくれるので便利。 標準streamのような沈黙を求める場合は代わりにstd::ifstream
などをpush()
する。- ファイル名に応じてフィルタを切り替えるようなクラスを定義しておけば、
透過的に読み書きできる。e.g.,
wtl::zfstream
program_options
https://www.boost.org/doc/libs/release/libs/program_options/
要ビルド&リンク -lboost_program_options-mt
cf. getopt
coroutine2
https://www.boost.org/doc/libs/release/libs/coroutine2/
要ビルド&リンク -lboost_context-mt
Pythonのyield
みたいなことをC++でもできるようになる。
example of Fibonacci generator
オブジェクトの寿命に注意。
yield
返しはmoveなので、 次の処理で再利用するつもりならコピーコンストラクタ越しに新品を返す。- generator的なものを返す関数を作ると、 それを抜ける時に寿命を迎えるオブジェクトがあることに注意。