I have a template class
template<class U, class V, class W> class S {
and some stock type implementations for types U , V and 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;
I want to check class S with all possible combinations of template arguments,
typedef boost::mpl::vector< S<U0,V0,W0>, S<U0,V0,W1>,
like this:
boost::mpl::for_each<s_types>(test_func).
The only problem is 2 ** 5 ** 5 = 50 combinations, which I do not want to enter one by one.
Is there a way to generate all combinations ( s_types ) using Boost :: mpl or Boost.Preprocessor?
thanks.
Added my initial unsuccessful attempts:
I tried to resort to indexes (therefore, defining u_types, etc.) and a partial specialized specialization by template, such as
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 }
then with
wrapper::S_Wrapper< mpl::size<u_types>::type::value, mpl::size<v_types>::type::value, mpl::size<w_types>::type::value > s;
all types S should be weighed and tested;
However, I could not cover all the combinations, defining
1) proper specializations and 2) recursive triggers in struct S_Wrapper
All my tests either ended with a partial coverage of combinations at runtime, or a failure of deduction during compilation.
Any thoughts?
Decision
Inspired by Matthieu, I came up with the Combine boilerplate class so that I can achieve my goal in two lines as follows:
typedef Combine< u_types, v_types, w_type, print_typeid >::Generate<> base_generator_type; base_generator_type::Run();
which will print all generated types.
the code
// 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, eg boost::mpl::vector class VTypes, // Forward Sequence, eg boost::mpl::vector class WTypes, // Forward Sequence, eg 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