Frage

Ich entwickle ein Programm, wo ich mich wie dies viel zu tun dies finden:

void Model::SetCollideMode( const std::string &m )
{
  Body *body;

  std::map<std::string, Body* >::iterator iter;

  for (iter=this->bodies.begin(); iter!=this->bodies.end(); iter++)
  {
    body = iter->second;

    body->SetCollideMode( m );
  }
}

Ich habe mehrere Methoden wie das in mehrere Objekt, das im Grunde eine Eigenschaft für all seine Kinder gelten. Von Ruby-Welt so etwas wie ich sterbe zu tun:

for_all_bodies{ body->SetCollideMode(m) }

Es ist sowieso diesen Code mehr Verschlüsse wie oder in anderer Art und Weise zu machen, verbessern das?

Ich bin bewusst, wie C ++ funktioniert, dass es Stack basiert und es gibt keine Kontextinformationen eine perfekte Schließung wie Funktionalität (diese müssen eine VM?), Aber zumindest verbessern über die aktuelle Wiederholung dieser Code 100mal Art zu schaffen, Programmierung.

War es hilfreich?

Lösung

Es gibt mehrere Ansätze, keiner von ihnen perfekt.

Als erstes würde der „konventionelle“ Ansatz einen Funktor zu definieren zu tun, was Sie brauchen:

struct SetCollideModeFunc {
  SetCollideModeFunc(const std::string& m) : m(m) {}
  void operator()(std::pair<std::string, Body*>& p) {
    Body* b = p.second;
    b->SetCollideMode(m);
  }

  const std::string& m;
};

void Model::SetCollideMode( const std::string &m )
{
  std::for_each(bodies.begin(), bodies.end(), SetCollideModeFunc(m));
}

Dies ist Sie eine Menge Code nicht retten, aber es erlaubt Ihnen die Iteration aus dem Betrieb zu trennen, die Sie anwenden möchten. Und wenn Sie collidemode mehrere Male festlegen müssen, können Sie die Funktors wiederzuverwenden, natürlich.

Eine kürzere Version ist möglich, mit der Boost.Lambda Bibliothek, die Sie den Funktors inline definieren erlauben würde. Ich kann nicht die genaue Syntax erinnern, wie ich Boost.Lambda nicht häufig verwenden, aber es wäre so etwas wie diese:

std::for_each(bodies.begin(), bodies.end(), _1.second->SetCollideMode(m));

In C ++ 0x, erhalten Sie Sprachunterstützung für Lambda-Ausdrücke, Syntax ermöglichen ähnlich wie dies ohne in Bibliotheken von Drittanbietern zu ziehen zu haben.

Schließlich Boost.ForEach könnte eine Option sein, die Syntax erlaubt wie folgt aus:

void Model::SetCollideMode(const std::string &m)
{
  BOOST_FOREACH ((std::pair<std::string, Body*> p), bodies) // note the extra parentheses. BOOST_FOREACH is a macro, which means the compiler would choke on the comma in the pair if we do not wrap it in an extra ()
  {
    p.second->SetCollideMode(m);
  }
}

Andere Tipps

In C ++ 0x, ja. Siehe hier. So wie Sie erraten haben, sind sie getan in die charakteristische C ++ Art und Weise, dh, wenn Sie versehentlich über einen Stapel Variable schließen und dann die Lambda-Objekt lassen überleben länger als der Stapel, dann undefiniert Verhalten, das Sie haben. Es ist eine ganz neue Art und Weise Ihr Programm zum Absturz zu bringen! Aber das ist unfair -. In vielerlei Hinsicht sind sie anspruchsvoller als Lambda-Ausdrücke in vielen anderen Sprachen, weil man das Ausmaß erklären kann, auf die sie erlaubt Zustand mutieren

Bis dahin gab es Versuche, das gleiche zu emulieren Sache , aber sie sind wahrscheinlich mehr Mühe, als sie wert sind.

BOOST_FOREACH (oder die neue Serie auf Basis Schleife) ist wahrscheinlich der Weg zu gehen, aber hier ist, wie ich normalerweise Lambda in der aktuellen Standard-Ansatz, tr1 binden mit:

#include <algorithm>
#include <functional>
using namespace std;

void Model::SetCollideMode( const std::string &m )
{
  for_each(bodies.begin(),bodies.end(),
           tr1::bind(&Body::SetCollideMode,
                     tr1::bind(&pair<std::string, Body*>::second, _1), m));
}

könnten Sie die Boost.Foreach :

#include <boost/foreach.hpp>

void Model::SetCollideMode(const std::string &m)
{
  typedef pair<std::string, Body*> body_t;
  BOOST_FOREACH (body_t& body, bodies)
  {
    body.second->SetCollideMode(m);
  }
}

C ++ noch nicht LAMBDA unterstützen. Ich manchmal diese Abhilfe verwenden:

#include <boost/bind.hpp>
void Model::SetCollideMode( const std::string &m )
{    
  typedef std::map<std::string, Body* > Bodies;
  struct Helper
  {
      static SetCollideMode(const std::pair<std::string, Body*> & value,
                            const std::string & m)
      {
          value.second->SetCollideMode(m);
      }
  };

  for_each(bodies.begin(),
           bodies.end(),
           boost::bind(Helper::SetCollideMode,_1, m));
}

Just my 2 cents ..

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top