簡単ではありませんが、これは間違いなく可能flags
です。 は実行時にしか分からないため、コンパイル時と実行時の計算を絡み合わせる必要があります。
以下は、任意の基本インターフェイス、基本クラス、および mixin で使用できる一般的なソリューションです。
// recursive case
template < typename Interface, typename BaseMixin,
typename It, typename End, typename WrappersToApply >
struct MixinCreatorIteration
{
static boost::shared_ptr< Interface > apply( int flags )
{
typedef typename mpl::deref< It >::type flag_to_wrapper;
typedef typename mpl::first< flag_to_wrapper >::type flag;
typedef typename mpl::second< flag_to_wrapper >::type wrapper;
if ( flags & flag::value ) // add current wrapper
{
return MixinCreatorIteration<
Interface,
BaseMixin, typename
mpl::next< It >::type,
End, typename
mpl::push_back<
WrappersToApply,
wrapper
>::type
>::apply( flags );
}
else // don't add current wrapper
{
return MixinCreatorIteration<
Interface,
BaseMixin, typename
mpl::next< It >::type,
End,
WrappersToApply
>::apply( flags );
}
}
};
//base case through partial template specialization
template < typename Interface, typename BaseMixin,
typename End, typename WrappersToApply >
struct MixinCreatorIteration< Interface, BaseMixin,
End, End, WrappersToApply >
{
static boost::shared_ptr< Interface > apply( int flags )
{
using mpl::placeholders::_1;
using mpl::placeholders::_2;
typedef typename
mpl::fold<
WrappersToApply,
BaseMixin,
mpl::apply1< _2, _1 >
>::type mixin;
return boost::make_shared< mixin >();
}
};
template < typename Interface, typename BaseMixin, typename WrapperMap >
struct MixinCreator
{
static boost::shared_ptr< Interface > apply( int flags )
{
return MixinCreatorIteration<
Interface,
BaseMixin, typename
mpl::begin< WrapperMap >::type, typename
mpl::end< WrapperMap >::type,
mpl::vector< >
>::apply( flags );
}
};
そして、ここにあなたの例に似たサンプルの使用があります:
boost::shared_ptr< MyInterface > create( int flags )
{
using namespace mpl::placeholders;
typedef mpl::map<
mpl::pair< mpl::int_< 0x01 >, AddOnA<_> >,
mpl::pair< mpl::int_< 0x02 >, AddOnB<_> >,
mpl::pair< mpl::int_< 0x04 >, AddOnC<_> >
> flag_to_wrapper;
return MixinCreator< MyInterface, MixinBase, flag_to_wrapper >::apply( flags );
}
int main()
{
create( 0x01 ); // creates AddOnA< MixinBase >
create( 0x02 ); // creates AddOnB< MixinBase >
create( 0x07 ); // creates AddOnC< AddOnB< AddOnA< MixinBase > > >
create( 0x08 ); // creates MixinBase
}
基本的には、フラグとラッパーの関係をコンパイル時のデータ構造 (ここではmpl::map
) に格納し、この構造を反復処理して、途中でラッパーを適用し続けるという考え方です。反復の最後に、すべてのラッパーが適用され、インスタンスが作成されます。
あなたの例では、構築にはパラメーターが必要です。C++ 11 を使用できる場合は、可変引数パラメーターと完全な転送を使用するように私のソリューションを簡単に適応させることができます。それ以外の場合は、プリプロセッサを使用してさまざまなバージョンのapply
関数を生成できます (方法については、 Boost.Preprocessorを参照してください)。