Heavy Watal

Boost — ほぼ標準C++ライブラリ

Installation

パッケージマネージャで

Homebrew/Linuxbrew で最新版を簡単にインストールできる。 オプションは適当に:

% brew install boost --c++11 --without-single

--layout=tagged でビルドされるため、 リンクするときは末尾に -mt が必要になる。

ソースから

  1. http://www.boost.org/users/download/ から最新ソースを入手して展開。

    % wget -O- https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2 | tar xj
    % cd boost_1_64_0/
    
  2. ビルドすべきライブラリを考える ./bootstrap.sh --show-libraries

  3. 適当なオプションを与えて bootstrap.sh を実行:

    % ./bootstrap.sh --help
    % ./bootstrap.sh --without-icu --with-libraries=coroutine2,filesystem,graph,iostreams,program_options,serialization,system,test
    

    設定が project-config.jam に書き出され、 b2 がビルドされる。 ./b2 --help

  4. ~/user-config.jamツールセットを定義darwinはMac-gcc用:

    using gcc : 14 : g++-6 : <compileflags>-fPIC <cxxflags>-std=c++14 ;
    using darwin : 14 : g++-6 : <compileflags>-fPIC <cxxflags>-std=c++14 ;
    using clang : 14 : clang++ : <compileflags>-fPIC <cxxflags>-std=c++14 -stdlib=libc++ <linkflags>-stdlib=libc++ ;
    

    gccとclangの両方から使える統一ライブラリを作るのは難しいらしいので、 それぞれのコンパイラで別々にビルドしてインストールする。

  5. システム標準zlibをリンクしようとしてエラーになるような場合は、 zlib公式からソースを落として展開し、 一緒にビルドされるように ZLIB_SOURCEをフルパス指定する。

    % wget -O- http://zlib.net/zlib-1.2.8.tar.gz | tar xz -C ${HOME}/tmp/build
    % export ZLIB_SOURCE=${HOME}/tmp/build/zlib-1.2.8
    
  6. ツールセットを指定してビルド:

    % ./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
    
  7. 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

distribution

確率分布に従った乱数生成は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

要ビルド&リンク -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;
    }
}

program_options

要ビルド&リンク -lboost_program_options-mt

cf. getopt

coroutine2

要ビルド&リンク -lboost_context-mt

PythonのyieldみたいなことをC++でもできるようになる。

Fibonacci generator on gist

オブジェクトの寿命に注意。

  • yield返しはmoveなので、 次の処理で再利用するつもりならコピーコンストラクタ越しに新品を返す。
  • generator的なものを返す関数を作ると、 それを抜ける時に寿命を迎えるオブジェクトがあることに注意。

そのほか

<boost/multiprecision/cpp_int.hpp>

<boost/dynamic_bitset.hpp>