【问题标题】:Is there a way to break out of boost::mpl for_each?有没有办法摆脱 boost::mpl for_each?
【发布时间】:2011-06-15 10:51:10
【问题描述】:

真的很简单的问题,让我提供一些背景:

我有一个 mpl::vector 类型,其中每个类型都有一个 id,在运行时我使用 mpl::for_each 遍历这个向量并找到给定 id 的匹配类型。但是一旦找到,继续循环就没有意义了,所以 - 问题是,有没有办法摆脱它(不抛出异常)?

【问题讨论】:

    标签: c++ templates boost boost-mpl


    【解决方案1】:

    为了实现find_if 之类的东西,我将for_each(称为exec_if)更改为采用bool 模板参数。 bool 表示执行是否应该与下一个序列一起执行,或者影响提前返回。

    #include <iostream>
    
    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/is_sequence.hpp>
    #include <boost/mpl/begin_end.hpp>
    #include <boost/mpl/apply.hpp>
    #include <boost/mpl/bool.hpp>
    #include <boost/mpl/next_prior.hpp>
    #include <boost/mpl/deref.hpp>
    #include <boost/type_traits/is_same.hpp>
    #include <boost/mpl/assert.hpp>
    
    namespace mpl = boost::mpl;
    
    template< bool done = true >
    struct exec_if_impl
    {
      template<typename Iterator, typename LastIterator, typename Pred, typename Exec>
      static void execute(Iterator*, LastIterator*, Pred const&, Exec const&)
      {
      }
    };
    
    template<>
    struct exec_if_impl<false>
    {
      template<typename Iterator, typename LastIterator, typename Pred, typename Exec>
      static void execute(Iterator*, LastIterator*, Pred const& f, Exec const& e)
      {
        typedef typename mpl::deref<Iterator>::type item;
    
        if (!f(static_cast<item*>(0)))
        {
          typedef typename mpl::next<Iterator>::type iter;
          exec_if_impl<boost::is_same<iter, LastIterator>::value>
            ::execute(static_cast<iter*>(0), static_cast<LastIterator*>(0), f, e);
        }    
        else
          e(static_cast<item*>(0));
      }
    };
    
    template<typename Sequence, typename Pred, typename Exec>
    inline
    void exec_if(Pred const& f, Exec const& e, Sequence* = 0)
    {
      BOOST_MPL_ASSERT(( mpl::is_sequence<Sequence> ));
    
      typedef typename mpl::begin<Sequence>::type first;
      typedef typename mpl::end<Sequence>::type last;
    
      exec_if_impl<boost::is_same<first,last>::value>
        ::execute(static_cast<first*>(0), static_cast<last*>(0), f, e);
    }
    
    namespace msg
    {
      struct m1 { enum { TYPE = 1 }; static const char* name() { return "m1"; } };
      struct m2 { enum { TYPE = 2 }; static const char* name() { return "m2"; } };
      struct m3 { enum { TYPE = 3 }; static const char* name() { return "m3"; } };
      struct m4 { enum { TYPE = 4 }; static const char* name() { return "m4"; } };
      struct m5 { enum { TYPE = 5 }; static const char* name() { return "m5"; } };
    }
    
    struct checker
    {
      checker(int chk_type) : type(chk_type) {}
    
      template <typename Mtype>
      bool operator()(Mtype* = 0) const
      {
        return Mtype::TYPE == type;
      }
    
      int type;
    };
    
    struct exec
    {
      template <typename Mtype>
      void operator()(Mtype* = 0) const
      {
        std::cout << Mtype::name() << " executed" << std::endl;
      }
    };
    
    int main(void)
    {
      typedef mpl::vector<msg::m1, msg::m2, msg::m3, msg::m4, msg::m5> mseq;
    
      checker chk(3); 
    
      exec_if<mseq>(chk, exec());
    
      return 0;
    }
    

    我将其更改为exec_if,所以现在当谓词匹配时,将使用类型触发要执行的函子 - 这正是我需要的。

    【讨论】:

      【解决方案2】:

      不,没有办法“破坏”mpl::for_each。话虽如此,我可能误解了你的问题,但在我看来,你需要mpl::find_ifmpl::for_each 更多:

      #include <boost/mpl/find_if.hpp>
      #include <boost/mpl/vector.hpp>
      
      template<int N>
      struct Foo { enum { id = N }; };
      
      template<int N>
      struct has_nested_id {
          template<class T>
          struct apply {
              static const bool value = (N == T::id);
          };
      };
      
      int main()
      {
          typedef boost::mpl::find_if
              <
                  boost::mpl::vector<Foo<1>, Foo<2>, Foo<3> >,
                  has_nested_id<3>::apply<boost::mpl::_1>
              >::type iterator_type;
      
          typedef boost::mpl::deref<iterator_type>::type type; // result is Foo<3>
      }
      

      【讨论】:

      • 我确实需要find_if,但需要一个运行时版本,而不是上面的元版本。我遇到的问题是 3 仅在运行时可用。
      • @Nim- MPL 仅适用于编译时构造,因为模板只能使用编译时已知的值进行实例化。如果您直到运行时才知道索引,您将不得不使用其他方法。
      • @templatetypedef,是的,我明白,我目前的方法是尝试找到for_each 的代码,看看我是否可以破解它,它以某种方式迭代类型是运行时,所以有成为一种方式......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-16
      • 1970-01-01
      • 2022-01-10
      • 2019-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多