這絕對是可能的,即使不是簡單:因爲flags
只知道在運行時,你需要糾結的編譯時間和運行時間計算。
這裏是一個通用的解決方案,它可以與任何基本接口,基類和混入使用:
// 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)。
不是我能想到的,假設只有在運行時才知道'flags'的值。 – ildjarn
@ildjarn - 是的,只有在運行時才知道標誌。 – PaulH
你需要各種標誌的所有組合嗎? –