是否可以使用模板参数的所有组合生成类型? [英] Is it possible to generate types with all combinations of template arguments?

查看:32
本文介绍了是否可以使用模板参数的所有组合生成类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板类

template<class U, class V, class W> 
class S
{
//... implementations 
};

以及UVW 类型的一些股票类型实现:

and some stock type implementations for type 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;

我想用模板参数的所有可能组合来测试类 S,

I want to test class S with all possible combinations of the template arguments,

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 个组合,我不想一一输入.

The only problem is there are 2 ** 5 ** 5 = 50 combinations that I do not wish to type in one by one.

有没有办法用 Boost::mpl 或 Boost.Preprocessor 生成所有组合(s_types)?

Is there a way to generate all the combinations(s_types) with Boost::mpl or Boost.Preprocessor?

谢谢.

添加了我最初的失败尝试:

Added my initial failed attempts:

我试图求助于索引(因此定义了 u_types 等)和像这样的部分模板特化

I was trying to resort to indexes(hence defining u_types and the like) and partial template specialization like this

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 类型都应该被生成和测试;

all S types should be gengerated and tested ;

但是我没有通过确定来覆盖所有的组合

However I failed to cover all the combination by determining

1) 适当的专业化和
2) struct S_Wrapper 中的递归性触发器

1) the proper specializations and
2) recursive-ness triggers in struct S_Wrapper

我所有的试验要么在运行时部分覆盖了组合,要么在编译时演绎失败.

All my trials either ended up in partial coverage of the combinations at runtime or deduction failure at compile time.

有什么想法吗?

受 Matthieu 的启发,我想出了一个模板化类 Combine,这样我就可以用 2 行代码实现我的目标:

Inspired by Matthieu, I've come up with a templated class Combine so that I could achieve my goal in 2 lines like this:

typedef Combine<
            u_types,
            v_types,
            w_type,
            print_typeid
        >::Generate<> base_generator_type;
base_generator_type::Run();

将打印所有生成的类型.

which will print all generated types.

// 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

推荐答案

如果你真正想做的是生成所有可能解决方案的向量然后测试它们,你将不得不使用预处理器为你生成它们.

If what you really want to do is generating the vector of all possibles solutions and then test them, you will have to use the preprocessor to generate them all for you.

然而,另一种解决方案是使用生成器:一个包装类,它将实例化您的所有解决方案并测试它们.您可能需要查阅 Loki 的层次结构生成器(书中有详细介绍).

However, another solution would consist into using a generator: a wrapper class which will instantiate all your solutions and test them. You might want to consult the Hierarchy Generators of Loki (detailed in the book).

// 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 指令......不过我希望你明白我的意思.

Disclaimer: this code has not been compiled and may lack some include / typename / use directives... nevertheless I hope you get my point.

如果您对什么是设计模式有任何了解,那么它在每个步骤层添加另一轮测试的方式与装饰器"或复合"设计非常相似.

If you have any idea of what the Design Patterns are, it is highly similar to a 'decorator' or a 'composite' design in its way of adding another round of tests at each step layer.

我还想指出,这需要 50 多行代码......但至少它会随着向量的增长而很好:)

I would also like to note that this takes more that 50 lines of code... but at least it will grow nicely with the vectors :)

这篇关于是否可以使用模板参数的所有组合生成类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆