11 Stimmen

Gibt es einen Weg, um aus boost::mpl for_each auszusteigen?

Eigentlich eine einfache Frage, lassen Sie mich etwas Hintergrundwissen geben:

Ich habe einen mpl::Vector von Typen, wobei jeder Typ eine ID hat; zur Laufzeit verwende ich mpl::for_each, um durch diesen Vektor zu iterieren und den passenden Typ für die gegebene ID zu finden. Aber sobald der Typ gefunden ist, hat es keinen Sinn, die Schleife fortzusetzen - die Frage ist also: Gibt es eine Möglichkeit, aus ihr auszubrechen (ohne eine Ausnahme zu werfen)?

6voto

Nim Punkte 32693

Um etwas Ähnliches wie find_if zu implementieren, habe ich das for_each geändert (es exec_if genannt), um ein bool Template-Argument anzunehmen. Das bool gibt an, ob die Ausführung mit den nächsten Sequenzen erfolgen soll oder ob sie effektiv vorzeitig zurückkehren soll.

#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace mpl = boost::mpl;

template< bool done = true >
struct exec_if_impl
{
  template
  static void execute(Iterator*, LastIterator*, Pred const&, Exec const&)
  {
  }
};

template<>
struct exec_if_impl
{
  template
  static void execute(Iterator*, LastIterator*, Pred const& f, Exec const& e)
  {
    typedef typename mpl::deref::type item;

    if (!f(static_cast(0)))
    {
      typedef typename mpl::next::type iter;
      exec_if_impl::value>
        ::execute(static_cast(0), static_cast(0), f, e);
    }    
    else
      e(static_cast(0));
  }
};

template
inline
void exec_if(Pred const& f, Exec const& e, Sequence* = 0)
{
  BOOST_MPL_ASSERT(( mpl::is_sequence ));

  typedef typename mpl::begin::type first;
  typedef typename mpl::end::type last;

  exec_if_impl::value>
    ::execute(static_cast(0), static_cast(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 
  bool operator()(Mtype* = 0) const
  {
    return Mtype::TYPE == type;
  }

  int type;
};

struct exec
{
  template 
  void operator()(Mtype* = 0) const
  {
    std::cout << Mtype::name() << " executed" << std::endl;
  }
};

int main(void)
{
  typedef mpl::vector mseq;

  checker chk(3); 

  exec_if(chk, exec());

  return 0;
}

Ich habe dies in exec_if geändert, sodass jetzt, wenn das Prädikat übereinstimmt, der Funktor zur Ausführung mit dem Typ ausgelöst wird - das tut genau das, was ich brauche.

4voto

icecrime Punkte 70619

Nein, es gibt keine Möglichkeit, ein mpl::for_each zu "unterbrechen". Das gesagt, ich könnte dein Problem missverstanden haben, aber es scheint mir, dass du eher mpl::find_if benötigst als mpl::for_each :

#include 
#include 

template
struct Foo { enum { id = N }; };

template
struct has_nested_id {
    template
    struct apply {
        static const bool value = (N == T::id);
    };
};

int main()
{
    typedef boost::mpl::find_if
        <
            boost::mpl::vector, Foo<2>, Foo<3> >,
            has_nested_id<3>::apply
        >::type iterator_type;

    typedef boost::mpl::deref::type type; // Ergebnis ist Foo<3>
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X