有没有办法摆脱 boost::mpl for_each ?

发布于 2024-10-14 05:57:29 字数 188 浏览 3 评论 0原文

确实很简单的问题,让我给出一些背景知识:

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

Simple question really, let me give some background:

I have a mpl::vector of types where each type has an id, at run time I use the mpl::for_each to iterate through this vector and find the matching type for the given id. But once found, there is no point in continuing the loop, so - question is, is there a way to break out of it (without throwing an exception)?

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

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

发布评论

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

评论(2

瞎闹 2024-10-21 05:57:29

为了实现类似 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 ,因此现在当谓词匹配时,将使用该类型触发要执行的函子 - 这正是我所需要的。

To implement something like find_if I changed the for_each (calling it exec_if) to take a bool template argument. The bool indicates if execution should with the next sequences, or in affect return early.

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

I changed this to exec_if, so now when the predicate matches, then the functor to execute will be triggered with the type - this does exactly what I need.

桜花祭 2024-10-21 05:57:29

不,没有办法“破坏”mpl::for_each。话虽这么说,我可能误解了你的问题,但在我看来你需要 mpl::find_if 多于 mpl::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>
}

Nope, there is no way to 'break' a mpl::for_each. That being said, I might have misunderstood your problem, but it seems to me you need mpl::find_if more than mpl::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>
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文