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

发布于 2024-08-06 07:09:09 字数 7296 浏览 11 评论 0原文

我有一个模板类

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

和一些类型 UVW 的库存类型实现:

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) 适当的专业化和
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<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

I have a templated class

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

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;

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;

like this:

boost::mpl::for_each<s_types>(test_func).

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

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

thanks.


Added my initial failed attempts:

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
}

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 S types should be gengerated and tested ;

However I failed to cover all the combination by determining

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.

Any thoughts?


Solution

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.


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柠檬色的秋千 2024-08-13 07:09:09

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

然而,另一种解决方案包括使用生成器:一个包装类,它将实例化所有解决方案并测试它们。您可能需要查阅 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 行代码...但至少它会随着向量一起很好地增长:)

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.

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();
}

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.

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 :)

挽手叙旧 2024-08-13 07:09:09

亲爱的马蒂厄,您的解决方案效果很好。
对于我的框架,我需要一种更通用的方法来实现类型组合,因此我开发了一些似乎可行的不同方法。
我在这里提出我的实施方案。我认为如果考虑到 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;
};

这从随机访问序列的序列创建新的前向序列。
提供序列开始和结束的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  

感谢您的关注。

安德里亚·里戈尼·加罗拉

Dear Matthieu your solution works fine.
For my framework I needed a more generic way to implement type combination so I developed something different that seems to work.
I propose here my implementation. I think it may be also more MPL oriented if you take the mpl view concept into account.
It provides the combination of type sequences as a special combine view and combine iterators:

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;
};

This creates a new fwd sequence from a sequence of random access sequences.
The combine_iterator that provides begin and end of the sequence must know both the sequences and the iterators that provide position, such as this implementation:

 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;
 };

Now you have to tell boost mpl how to reach the next position specializing mpl::next operation.

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

Finally the combiner trick can be implemented using mpl::fold like in this class:

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;
};

Let me show you how to use the resulting new sequence view in a test app.

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;
}

The result should be something like this:

..:: 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  

Thanks for your Attention.

Andrea Rigoni Garola

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文