Pergunta

Estou desenvolvendo um programa onde eu me vejo fazendo isso como muito isso:

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

Eu tenho vários métodos, como que em vários objeto que basicamente se aplicam uma propriedade para todos os seus filhos. Vindo de rubi mundo que eu estou morrendo de vontade de fazer algo como:

for_all_bodies{ body->SetCollideMode(m) }

Não há qualquer maneira de fazer esse código mais fechamentos similares ou em outra maneira melhorá-lo?

Estou consciente de como funciona a C ++, que é baseado em pilha e não há nenhuma informação de contexto para criar um fecho perfeito como funcionalidade (essa necessidade de uma VM?) Mas pelo menos melhorar ao longo da repetição actual este código 100 vezes tipo de programação.

Foi útil?

Solução

Existem várias abordagens, nenhum deles aperfeiçoar.

Em primeiro lugar, a abordagem "convencional" seria definir um functor de fazer o que você precisa:

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

Isto não te salvar um monte de código, mas permite que você separe a iteração da operação que você deseja aplicar. E se você precisa definir collidemode várias vezes, você pode reutilizar o functor, é claro.

Uma versão mais curta é possível com a biblioteca Boost.Lambda, o que lhe permitiria definir a linha functor. Não me lembro a sintaxe exata, como eu não usar Boost.Lambda muitas vezes, mas seria algo como isto:

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

Em ++ 0x C, você tem suporte ao idioma para lambdas, permitindo sintaxe semelhante a este, sem ter que puxar as bibliotecas de terceiros.

Finalmente, Boost.ForEach pode ser uma opção, permitindo sintaxe como esta:

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

Outras dicas

Em C ++ 0x, sim. Veja aqui. Assim como você adivinhou, eles são feitos em a característica C ++ forma, ou seja, se você acidentalmente perto sobre uma variável de pilha e, em seguida, deixar o objeto lambda sobreviver mais tempo do que a pilha, então você tem um comportamento indefinido. É toda uma nova maneira de fazer o seu programa falhar! Mas isso é injusto -., Em muitos aspectos eles são mais sofisticados do que lambdas em muitas outras línguas, porque você pode declarar a medida em que eles estão autorizados a estado de mutação

Até então, tem havido tentativas de emular o mesmo coisa , mas eles são provavelmente mais problemas do que eles valem.

BOOST_FOREACH (ou o novo circuito baseado gama) é provavelmente o caminho a percorrer, mas aqui está como eu normalmente aproximar lambda no padrão atual, usando tr1 dilema:

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

Você pode usar o 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 ++ ainda não suporta lambda de. Às vezes eu usar essa solução alternativa:

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

Apenas meus 2 centavos ..

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top