当前位置:  开发笔记 > 编程语言 > 正文

是否可以使用模板参数的所有组合生成类型?

如何解决《是否可以使用模板参数的所有组合生成类型?》经验,为你挑选了1个好方法。

我有一个模板课

template 
class S
{
//... implementations 
};

和类型的一些股票类型实现U,VW:

typedef boost::mpl::vector u_types;
typedef boost::mpl::vector u_types;
typedef boost::mpl::vector w_types;

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

typedef boost::mpl::vector<
    S, 
    S,
    // ...
    S,
    > s_types;

像这样:

boost::mpl::for_each(test_func).

唯一的问题是有2**5**5 = 50种组合,我不希望逐个输入.

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

谢谢.


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

我试图诉诸索引(因此定义u_types等)和部分模板专业化这样

namespace wrapper
{
  template  
  struct S_Wrapper
  {
    typedef S type;

    S_Wrapper() // auto test in the ctor
    {
      cout << "test result = " << test(type());
    }

    // test with S
    static bool test(type t)
    {
      // implementations
    }

    // get stuck here, 
    S_Wrapper 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
    //
    static bool test(type t)
    {
      // implementations
    }  
  };

  // get stuck here, too
  // what other specializations are ?
  // other specializations
}

然后用

wrapper::S_Wrapper< 
  mpl::size::type::value, 
  mpl::size::type::value, 
  mpl::size::type::value
> s; 

所有S类型都应进行调整和测试;

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

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

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

有什么想法吗?


受到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::type v_begin;
            typedef typename begin::type w_begin;

            typedef typename end::type u_end;
            typedef typename end::type v_end;
            typedef typename end::type w_end;

            typedef typename next::type u_next;
            typedef typename next::type v_next;
            typedef typename next::type w_next;

            typedef typename if_< is_same,
                                typename if_< is_same,
                                    typename if_< is_same,
                                        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::type,
            class VIterator = typename begin::type,
            class WIterator = typename begin::type
        >
        struct Generate
        {
            //  generate <> 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::type,
                     typename deref::type,
                     typename deref::type
                 >();

                // go to the next round of recursion
                next_type::Run();
            }
        };
    };

}//  namespace argument_combination

Matthieu M... 9

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

但是,另一个解决方案是使用生成器:一个包装类,它将实例化所有解决方案并测试它们.您可能想咨询Loki的层次结构生成器(详细信息在本书中).

// never remember where they put boost::same_type :x
#include 
#include 
#include 
#include 
#include 

using namespace boost::mpl;

struct None
{
   static void test() {}
};

template 
class Generator;

template 
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::type v_begin;
  typedef typename begin::type w_begin;

  typedef typename next::type u_next;
  typedef typename next::type v_next;
  typedef typename next::type w_next;

  typedef typename end::type u_end;
  typedef typename end::type v_end;
  typedef typename end::type w_end;


  typedef if_< boost::same_type,
               if_< boost::same_type,
                    if_< boost::same_type,
                         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 
struct Generator
{
   typedef S< deref::type,
              deref::type,
              deref::type > S_type;

   typedef Next::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::type, u_types,
                     begin::type, v_types,
                     begin::type, w_types > base_generator_type;

  base_generator_type::test();
}

免责声明:此代码尚未编译,可能缺少一些include/typename/use指令......但我希望你明白我的观点.

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

我还要注意,这需要更多的50行代码...但至少它会与矢量很好地成长:)



1> Matthieu M...:

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

但是,另一个解决方案是使用生成器:一个包装类,它将实例化所有解决方案并测试它们.您可能想咨询Loki的层次结构生成器(详细信息在本书中).

// never remember where they put boost::same_type :x
#include 
#include 
#include 
#include 
#include 

using namespace boost::mpl;

struct None
{
   static void test() {}
};

template 
class Generator;

template 
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::type v_begin;
  typedef typename begin::type w_begin;

  typedef typename next::type u_next;
  typedef typename next::type v_next;
  typedef typename next::type w_next;

  typedef typename end::type u_end;
  typedef typename end::type v_end;
  typedef typename end::type w_end;


  typedef if_< boost::same_type,
               if_< boost::same_type,
                    if_< boost::same_type,
                         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 
struct Generator
{
   typedef S< deref::type,
              deref::type,
              deref::type > S_type;

   typedef Next::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::type, u_types,
                     begin::type, v_types,
                     begin::type, w_types > base_generator_type;

  base_generator_type::test();
}

免责声明:此代码尚未编译,可能缺少一些include/typename/use指令......但我希望你明白我的观点.

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

我还要注意,这需要更多的50行代码...但至少它会与矢量很好地成长:)

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有