読者です 読者をやめる 読者になる 読者になる

にゃははー

はへらー

Boost 1.50.0で追加されたライブラリ達

皆さんご存知の通りBoost 1.50.0がリリースされました。
このリリースで皆さん当然user-config.jamに BOOST_THREAD_VERSION=3 を追加したことと思います。

まぁ今回は変更ではなくて新しく追加されたライブラリについて。
Boost.Algorithmさんには若干失望してるので扱いません。

今回紹介する3ライブラリの作者はLorenzo Caminitiです。

Boost.Utility/IdentityType

Boost.Utility/IdentityType 1.0.0 - Boost 1.50.0

このライブラリはマクロを多用する人向けのライブラリです。これ自体は簡単なラッパーとなっています。

例えば特殊化をマクロを使って生成したりするパターン。以下の様なゴミコードが例。

template <typename T>
struct is_fuga : public boost::false_type {};

#define IS_FUGA_SPEC(type_) \
	template <> struct is_fuga<type_> : public boost::true_type {}

IS_FUGA_SPEC(int);
IS_FUGA_SPEC(std::pair<int, int>);

このコードがどのような問題があるかわからないようだったら実際にコンパイルしてみて下さい。というかプリプロセスですが。

とか言いながら結論を言うと2つ目のstd::pair<int, int>を投げたほうがエラーになります。
というのも IS_FUGA_SPEC(std::pair<int, int>) は std::pair<int という引数と int> という引数が渡されたと解釈されIS_FUGA_SPECには2引数渡せねぇよって怒られます。

Boost.Utility/IdentityTypeはこのような問題を回避することができます。
使ってみましょう。IS_FUGA_SPECは先の定義を使い回すとします。

#include <boost/utility/identity_type.hpp>
IS_FUGA_SPEC(BOOST_IDENTITY_TYPE((std::pair<int, int>)));

若干長くなった感ありますがこれで意図した通り std::pair<int, int> の特殊化をマクロを使って定義できます。

こいつは何をやってるのでしょうか。2重になっている括弧がミソです。
実際のとは違いますが中身を書いてみます。

template <typename> struct identity_type_impl;
template <typename T> struct identity_type_impl<void(T)> { typedef T type; }
#define BOOST_IDENTITY_TYPE(parenthesized_type_) \
	identity_type_impl<void parenthesized_type_>::type

たったこれだけです。

さっきの例を上の定義に当てはめて展開してみて下さい。よくできてることが分かると思います。
ちなみにプリプロセッサは ( から ) までを1つのトークン列として扱います。

この2重括弧は見覚えがあるのではないでしょうか。

BOOST_MPL_ASSERT((boost::is_same<int, void>));
BOOST_CONCEPT_ASSERT((boost_consepts::RandomAccessTraversal<RandomAccessIterator>));

まぁどれも同じ理由で2重になってるんですね。

あっ、あとdepending nameの場合は

BOOST_IDENTITY_TYPE((typename remove_reference<T>::type))
typename BOOST_IDENTITY_TYPE((remove_reference<T>))::type

好きな方でokです。(remove_refernece程度ならそもそもいらないですがそこはアレですよ。察せ

Boost.LocalFunction

Chapter 1. Boost.LocalFunction 1.0.0 - Boost 1.50.0

これはみなさん待ち望んだ感じのローカル関数です。

単なるラッパーだと思ってたのですがこないだドキュメント眺めてめちゃくちゃ強力なセマンティクスを提供してるのを知って衝撃受けてます。そして思ってた設計と全然違って実現方法が全然わからないです。。。あとで細かく追わないと...
わからないので特に説明しないです。

#include <iostream>

#include <boost/local_function.hpp>

template <typename F> void exec(F f) { f(1); }

int main()
{
	void BOOST_LOCAL_FUNCTION(int i)
	{
		std::cout << i << std::endl;
	} BOOST_LOCAL_FUNCTION_NAME(f)
	exec(f);
}

なんでtemplate parameterに突っ込めるんだろう...

Boost.Functional/OverloadedFunction

Chapter 1. Boost.Functional/OverloadedFunction 1.0.0 - Boost 1.50.0

これはC11の_Genericsに近いです。
複数の関数を束ねて1つのオーバーロードされた関数に見せかけるものです。

特に例も思いつかないのでサンプルそのまま転載です。手抜きです。

const std::string& identity_s(const std::string& x) // Function (as pointer).
    { return x; }

int identity_i_impl(int x) { return x; }
int (&identity_i)(int) = identity_i_impl; // Function reference.

double identity_d_impl(double x) { return x; }
boost::function<double (double)> identity_d = identity_d_impl; // Functor.

boost::overloaded_function<
      const std::string& (const std::string&)
    , int (int)
    , double (double)
> identity(identity_s, identity_i, identity_d);

// All calls via single `identity` function.
BOOST_TEST(identity("abc") == "abc");
BOOST_TEST(identity(123) == 123);
BOOST_TEST(identity(1.23) == 1.23);

で、こいつと先のBoost.LocalFunctionは組み合わせることでローカルなのにオーバーロードされた関数を作ることができます。
まぁわかると思うので例は出さないですが。

conclusion

全体的に地味なのが多いので一般ウケはしないだろうけどそれなりなものが来てます。使いましょう。
そして1.55.0にとっととならないですかね。