Boost.Serialization の Singleton のワナ
Boost.Serialization はシリアライズ機能を提供するライブラリだが、
同時に strong-typedef や static-warning など非常に便利な小道具を用意している。
その中で boost::serialization::singleton クラステンプレートは、
有名な(悪名も)シングルトンパターンを実装する。
詳細な解説は、ここに書くより下記の記事を参照したほうが早い。
-
- [redboltzの日記] boost::serializationで利用されているsingletonに関して
http://d.hatena.ne.jp/redboltz/20100226/1267140671
さて、公式のドキュメントにも概ね下のような Example がある。
(クラス名など多少書き換えてある)
class Foo : public boost::serialization::singleton<Foo> { friend class boost::serialization::singleton<Foo>; private: // private constructor to inhibit any existence other than the // static one. Note: not all compilers support this !!! Foo() {} ~Foo() {} public: void do_something() {} }; Foo::get_mutable_instance().do_something();
残念ながら上記コードはコンパイルできない(Boost 1.44 + VC9)
クラス中の friend 宣言は、boost::serialization::singleton
Foo のコンストラクタにアクセスできるようにするためであるが、
実際に Foo のコンストラクタへのアクセスを必要としているのは
detail:: 内の singleton_wrapper
#include <boost/serialization/singleton.hpp> class Foo : public boost::serialization::singleton<Foo> { // friend class boost::serialization::singleton<Foo>; /* ダメ */ friend class boost::serialization::detail::singleton_wrapper<Foo>; /* こっちを friend */ private: // private constructor to inhibit any existence other than the // static one. Note: not all compilers support this !!! Foo() {} ~Foo() {} public: void do_something() {} }; Foo::get_mutable_instance().do_something();
上記のように、friend 宣言を変更することでコンパイルが通る。
これはバグというより、実装の変更にあわせてドキュメントが更新されなかったことによる
食い違いだと思われる。(ずっと遡って検証したわけではないが)
いずれにせよ、ライブラリの detail:: 内に触れるというのは気持ちのいいものでない。