سؤال

وأنا تطوير برنامج أين أجد نفسي القيام بذلك مثل هذا كثيرا:

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

ولدي العديد من الطرق مثل هذا في العديد من الكائنات التي تطبق أساسا خاصية لجميع أبنائه. القادمة من Ruby العالم أنا الموت أن تفعل شيئا مثل:

for_all_bodies{ body->SetCollideMode(m) }

وهناك على أية حال لجعل هذا الرمز المزيد من الإغلاقات مثل أو بطريقة أخرى تحسين ذلك؟

وأنا ندرك كيف يعمل C ++، وهذا هو المكدس يقوم وليس هناك معلومات السياق إلى إنشاء إغلاق الكمال مثل وظيفة (وهذا بحاجة إلى VM؟) ولكن تحسين على الأقل خلال تكرار الحالي هذا الرمز 100 مرة نوع من البرمجة.

هل كانت مفيدة؟

المحلول

وهناك العديد من الطرق، فإن أيا منها الكمال.

أولا، نهج "التقليدية" سيكون لتحديد functor لتفعل ما تريد:

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

وهذا لا يوفر لك الكثير من التعليمات البرمجية، ولكنها لا تسمح لك لفصل التكرار من العملية التي تريد تطبيق. وإذا كنت تحتاج إلى تعيين collidemode عدة مرات، يمكنك إعادة استخدام functor، بطبيعة الحال.

وهناك نسخة أقصر ممكن مع مكتبة Boost.Lambda، التي من شأنها أن تسمح لك لتحديد مضمنة functor. لا أستطيع أن أتذكر بناء الجملة الصحيح، وأنا لا تستخدم Boost.Lambda في كثير من الأحيان، ولكنها تريد ان تكون شيئا من هذا القبيل:

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

في C ++ 0X، وتحصل على دعم اللغة لlambdas، مما يتيح تركيب مماثل لهذا دون الحاجة إلى سحب في المكتبات طرف ثالث.

وأخيرا، قد يكون Boost.ForEach خيارا، مما يتيح تركيب مثل هذا:

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

نصائح أخرى

في C ++ 0X، نعم. انظر هنا. تماما كما كنت قد خمنت، يتم القيام به في والمميز C ++ الطريقة، أي إذا قمت بإغلاق بطريق الخطأ على متغير كومة ومن ثم السماح للكائن امدا البقاء على قيد الحياة لفترة أطول من كومة، والسلوك ثم لديك غير معروف. انها طريقة جديدة كاملة لجعل تحطم البرنامج الخاص بك! ولكن هذا غير عادل - في نواح كثيرة أنها أكثر تطورا من lambdas في العديد من اللغات الأخرى، لأنك يمكن أن تعلن المدى الذي يسمح لهم لتتحول الدولة

وحتى ذلك الحين، كانت هناك محاولات لمحاكاة نفسه شيء ، ولكنهم ربما أكثر صعوبة من انهم قيمتها.

وBOOST_FOREACH (أو حلقة جديدة تقوم المدى) هو على الارجح وسيلة للذهاب، ولكن هنا هو كيف أنا عادة نهج امدا في المعيار الحالي، وذلك باستخدام TR1 مأزق:

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

هل يمكن استخدام 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 ++ لم تتوفر لامدا ل. أنا في بعض الأحيان استخدام هذا الحل:

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

و2 سنتا فقط بلدي ..

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top