サンプルの動作確認バージョン [GCC4.4/1.41.0] [VC9/1.41.0]
// boost::optional的な物の再開発
#include <new>
#include <boost/utility/in_place_factory.hpp>
template<typename T>
class my_optional
{
public:
my_optional() : storage(0) {}
template<class InPlace>
my_optional( const InPlace& p )
: storage(reinterpret_cast<T*>(new char[sizeof(T)]))
{ p.template apply<T>(storage); }
~my_optional() { delete storage; }
operator bool() { return storage!=0; }
T& operator*() { return *storage; }
private:
T* storage;
};
// てすとてすと
struct X
{
X(int,int) {}
};
int main()
{
my_optional<X> a;
my_optional<X> b(boost::in_place(100,200));
}
なにがやりたいかというと、my_optionalのコンストラクタで、storageを初期化したいのです。 もっとも簡単なやり方は
my_optional( const T& obj ) : storage(new T(obj)) {}
と、別のTのオブジェクトを受け取って、コピーコンストラクタを使って初期化する方法。 でもこれだと、まず、そもそもTにコピーコンストラクタがない場合に困ります。あと、 本来は不要なコピーが1回発生するので、なんだか無駄です。
別の方法としては
template<typename P1>
my_optional( P1& p1 ) : storage(new T(p1)) {}
template<typename P1,typename P2>
my_optional( P1& p1, P2& p2 ) : storage(new T(p1,p2)) {}
...
と、T用の引数を取るコンストラクタを大量に並べておく方法があります。 これは機能面でデメリットはありませんが、単純に、面倒ですし読みにくいです。
こういう場面で、in_place_factoryが使えます。 in_place() に指定した引数を覚えておいて、あとで apply するとその引数でコンストラクタを呼んでくれます。 おそらく、↑こういう割と特殊なものを作る場合にしか必要にならないライブラリですが…。