我有一个模板类
template<class U, class V, class W>
class S
{
//... implementations
};
以及类型U
,V
和W
的一些股票类型实现:
typedef boost::mpl::vector<U0, U1> u_types;
typedef boost::mpl::vector<V0, V1, V2, V3, V4> u_types;
typedef boost::mpl::vector<W0, W1, W2, W3, W4> w_types;
我想用模板参数的所有可能组合测试类S,
typedef boost::mpl::vector<
S<U0,V0,W0>,
S<U0,V0,W1>,
// ...
S<U1,V4,W4>,
> s_types;
像这样:
boost::mpl::for_each<s_types>(test_func).
唯一的问题是有2 ** 5 ** 5 = 50种组合,我不想逐一输入。
有没有办法用Boost :: mpl或Boost.Preprocessor生成所有组合(s_types
)?
感谢。
添加了我最初的失败尝试:
我试图求助于索引(因此定义u_types之类)和部分模板专门化这样
namespace wrapper
{
template <int Uidx, int Vidx, int Widx>
struct S_Wrapper
{
typedef S<Uidx, Vidx, Widx> type;
S_Wrapper() // auto test in the ctor
{
cout << "test result = " << test(type());
}
// test with S<Uidx, Vidx, Widx>
static bool test(type t)
{
// implementations
}
// get stuck here,
S_Wrapper<Uidx-1, Vidx, Widx> s; // temp varible to invoke recursive-ness
// what else to complete all recursive path?
};
// specializations
template <0, 0, 0>
struct S_Wrapper
{
typedef S<0, 0, 0> type;
// test with S<Uidx, Vidx, Widx>
//
static bool test(type t)
{
// implementations
}
};
// get stuck here, too
// what other specializations are ?
// other specializations
}
然后用
wrapper::S_Wrapper<
mpl::size<u_types>::type::value,
mpl::size<v_types>::type::value,
mpl::size<w_types>::type::value
> s;
所有S类型都应进行调整和测试;
然而,我未能通过确定
来涵盖所有组合 1)正确的专业和我的所有试验要么在运行时部分覆盖组合,要么在编译时扣除失败。
有什么想法吗?
受到Matthieu的启发,我想出了一个模板化的课程Combine
,这样我就能在这两行中实现我的目标:
typedef Combine<
u_types,
v_types,
w_type,
print_typeid
>::Generate<> base_generator_type;
base_generator_type::Run();
将打印所有生成的类型。
// example test implementation
struct print_typeid
{
template<
class U,
class V,
class W
>
static void run()
{
// print the typeinfo
std::cout
<< total_recursions << ":"
<< typeid(U).name() << ","
<< typeid(V).name() << ","
<< typeid(W).name()
<< std::endl;
}
};
// solution implemented in one wrapper class
namespace argument_combination
{
using boost::is_same;
using boost::mpl::begin;
using boost::mpl::end;
using boost::mpl::next;
using boost::mpl::if_;
using boost::mpl::deref;
unsigned int total_recursions = 0;
struct end_of_recursion_tag
{
static void Run()
{
std::cout << "end of "
<< total_recursions
<< " recursions\n"
;
}
};
template <
class UTypes, // Forward Sequence, e.g. boost::mpl::vector
class VTypes, // Forward Sequence, e.g. boost::mpl::vector
class WTypes, // Forward Sequence, e.g. boost::mpl::vector
class TestFunc // class type that has a nested templated run() member function
>
struct Combine
{
// forward declaration
template <
class UIterator,
class VIterator,
class WIterator
>
class Generate;
// this class implements recursion body
template <
class UIterator,
class VIterator,
class WIterator
>
struct Next
{
// u_begin is not necessary ;)
// it would be cheaper not to pre-declare all of them since we force evaluation
// however this dramatically increase the readability
typedef typename begin<VTypes>::type v_begin;
typedef typename begin<WTypes>::type w_begin;
typedef typename end<UTypes>::type u_end;
typedef typename end<VTypes>::type v_end;
typedef typename end<WTypes>::type w_end;
typedef typename next<UIterator>::type u_next;
typedef typename next<VIterator>::type v_next;
typedef typename next<WIterator>::type w_next;
typedef typename if_< is_same<typename w_next, w_end>,
typename if_< is_same<v_next, v_end>,
typename if_< is_same<u_next, u_end>,
end_of_recursion_tag,
Generate<
u_next,
v_begin,
w_begin
>
>::type,
Generate<
UIterator,
v_next,
w_begin
>
>::type,
Generate<
UIterator,
VIterator,
w_next
>
>::type type;
};
// this class run test on generated types in thos round and go to next*/
template <
class UIterator = typename begin<UTypes>::type,
class VIterator = typename begin<VTypes>::type,
class WIterator = typename begin<WTypes>::type
>
struct Generate
{
// generate <<next>> target type
typedef typename Next<
UIterator,
VIterator,
WIterator
>::type next_type;
static void Run()
{
// increment recursion counter
++total_recursions;
// test on the generated types of this round of recursion
TestFunc::run<
typename deref<UIterator>::type,
typename deref<VIterator>::type,
typename deref<WIterator>::type
>();
// go to the next round of recursion
next_type::Run();
}
};
};
}// namespace argument_combination
答案 0 :(得分:9)
如果你真正想做的是生成所有可能解决方案的向量然后测试它们,你将不得不使用预处理器为你生成所有这些解决方案。
然而,另一个解决方案将包括使用生成器:一个包装类,它将实例化所有解决方案并测试它们。您可能想咨询Loki的层次结构生成器(详见书中)。
// never remember where they put boost::same_type :x
#include <boost/mpl/if.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/next.hpp>
using namespace boost::mpl;
struct None
{
static void test() {}
};
template <class UIterator, class UTypes,
class VIterator, class VTypes,
class WIterator, class WTypes>
class Generator;
template <class UIterator, class UTypes,
class VIterator, class VTypes,
class WIterator, class WTypes>
struct Next
{
// u_begin is not necessary ;)
// it would be cheaper not to pre-declare all of them since we force evaluation
// however this dramatically increase the readability
typedef typename begin<VIterator>::type v_begin;
typedef typename begin<WIterator>::type w_begin;
typedef typename next<UIterator>::type u_next;
typedef typename next<VIterator>::type v_next;
typedef typename next<WIterator>::type w_next;
typedef typename end<UIterator>::type u_end;
typedef typename end<VIterator>::type v_end;
typedef typename end<WIterator>::type w_end;
typedef if_< boost::same_type<w_next, w_end>,
if_< boost::same_type<v_next, v_end>,
if_< boost::same_type<u_next, u_end>,
None,
Generator< u_next, UTypes,
v_begin, VTypes,
w_begin, WTypes >
>,
Generator< UIterator, UTypes,
v_next, VTypes,
w_begin, WTypes >
>,
Generator< UIterator, UTypes,
VIterator, VTypes,
w_next, WTypes>
>::type type;
};
template <class UIterator, class UTypes,
class VIterator, class VTypes,
class WIterator, class WTypes>
struct Generator
{
typedef S< deref<UIterator>::type,
deref<VIterator>::type,
deref<WIterator>::type > S_type;
typedef Next<UIterator, UTypes,
VIterator, VTypes,
WIterator, WTypes>::type next_type;
static void test()
{
// test my variation of S
S_Type my_S;
test_func(my_S);
// test the variations of my next and its next and... you get the idea :)
next_type::test();
}
};
// And finally
int main(int argc, char* argv[])
{
typedef Generator< begin<u_types>::type, u_types,
begin<v_types>::type, v_types,
begin<w_types>::type, w_types > base_generator_type;
base_generator_type::test();
}
免责声明:此代码尚未编译,可能缺少一些include / typename / use指令......但我希望你明白我的观点。
如果您对设计模式有什么了解,它就会在每个步骤层添加另一轮测试的方式与“装饰器”或“复合”设计高度相似。
我还要注意,这需要50行以上的代码...但至少它会与矢量一起很好地发展:)
答案 1 :(得分:1)
亲爱的Matthieu您的解决方案正常。 对于我的框架,我需要一种更通用的方式来实现类型组合,所以我开发了一些似乎有用的东西。 我在这里提出我的实施。如果考虑到mpl视图概念,我认为它可能也更加面向MPL。 它提供了类型序列的组合作为特殊的组合视图并组合迭代器:
template < class Seq >
class combine_view {
typedef typename mpl::transform<Seq, mpl::begin<_1> >::type Pos_begin;
typedef typename mpl::transform<Seq, mpl::end<_1> >::type Pos_end;
public:
typedef combine_iterator<Seq, Pos_begin> begin;
typedef combine_iterator<Seq, Pos_end> end;
typedef combine_view type;
};
这将从一系列随机访问序列创建一个新的fwd序列。 提供序列开始和结束的combine_iterator必须知道序列和提供位置的迭代器,例如此实现:
template < typename Seq, typename Itrs >
struct combine_iterator {
typedef mpl::forward_iterator_tag category;
typedef Seq seq;
typedef typename transform <
Itrs,
deref<_1>
>::type
type;
};
现在你必须告诉boost mpl如何到达专门的mpl :: next操作的下一个位置。
namespace boost {
namespace mpl {
template <class Seq, class Pos>
struct next< combine_iterator<Seq, Pos> > {
typedef typename SequenceCombiner<Seq,Pos>::next next_Pos;
typedef combine_iterator< Seq, next_Pos > type;
};
} // mpl
} // boost
最后,组合器技巧可以使用mpl :: fold实现,就像在这个类中一样:
template <class Seq, class ItrSeq>
class SequenceCombiner {
template < class _Seq = mpl::vector<int_<1> > >
struct StateSeq {
typedef typename pop_front<_Seq>::type sequence;
typedef typename mpl::at< _Seq, int_<0> >::type state;
typedef _Seq type;
};
template < class _Seq, class _State >
struct set_state {
typedef StateSeq< typename push_front<_Seq, _State >::type > type;
};
struct NextOp {
template < typename Out, typename In, typename Enable = typename Out::state >
class apply {
typedef typename Out::sequence seq;
typedef typename Out::state new_state;
typedef typename mpl::at<In,int_<0> >::type in_seq;
typedef typename mpl::at<In,int_<1> >::type in_itr;
typedef typename mpl::push_back<seq, in_itr >::type new_seq;
public:
typedef typename set_state<new_seq, int_<0> >::type type;
};
template < typename Out, typename In >
class apply<Out,In,mpl::int_<1> > {
typedef typename Out::sequence seq;
typedef typename Out::state state;
typedef typename mpl::at<In,int_<0> >::type in_seq;
typedef typename mpl::at<In,int_<1> >::type in_itr;
typedef typename mpl::begin<in_seq>::type Itr_begin;
typedef typename mpl::next<in_itr>::type Itr_next;
typedef typename mpl::end<in_seq>::type Itr_end;
typedef typename mpl::if_< boost::is_same<Itr_next,Itr_end>,
typename mpl::push_back<seq,Itr_begin>::type,
typename mpl::push_back<seq,Itr_next>::type
>::type
new_seq;
typedef typename mpl::if_< boost::is_same<Itr_next,Itr_end>,
mpl::int_<1>,
mpl::int_<0>
>::type
new_state;
public:
typedef typename set_state<new_seq, new_state>::type type;
};
};
typedef typename mpl::fold<
typename mpl::zip_view< mpl::vector<Seq, ItrSeq > >::type,
StateSeq<>,
NextOp
>::type
StateResult;
public:
typedef typename mpl::if_< boost::is_same< typename StateResult::state, int_<1> >,
typename mpl::transform< Seq, mpl::end<_1> >::type,
typename StateResult::sequence >::type
next;
};
让我向您展示如何在测试应用中使用生成的新序列视图。
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
struct F {};
struct G {};
struct H {};
struct I {};
namespace {
struct PrintTypeId {
template <class T>
void operator()(T) const
{ std::cout << typeid(T).name() << " "; }
};
struct PrintSeq {
template < typename T >
void operator()(T) {
mpl::for_each<T>( PrintTypeId() );
std::cout << "\n";
}
};
}
int main() {
BEGIN_TESTING( Mpl Sequence Combiner Test);
typedef mpl::vector<A,B,C> seq1;
typedef mpl::vector<D,E,F> seq2;
typedef mpl::vector<G,H,I> seq3;
typedef mpl::combine_view< mpl::vector<seq1,seq2,seq3> > cv;
mpl::for_each< cv >( PrintSeq() );
END_TESTING;
}
结果应该是这样的:
..:: Testing Mpl Sequence Combiner Test ::..
1A 1D 1G
1B 1D 1G
1C 1D 1G
1A 1E 1G
1B 1E 1G
1C 1E 1G
1A 1F 1G
1B 1F 1G
1C 1F 1G
1A 1D 1H
1B 1D 1H
1C 1D 1H
1A 1E 1H
1B 1E 1H
1C 1E 1H
1A 1F 1H
1B 1F 1H
1C 1F 1H
1A 1D 1I
1B 1D 1I
1C 1D 1I
1A 1E 1I
1B 1E 1I
1C 1E 1I
1A 1F 1I
1B 1F 1I
1C 1F 1I
感谢您的关注。
Andrea Rigoni Garola