C ++ лямбда-выражение для цепочек методов - PullRequest
3 голосов
/ 03 декабря 2011

Допустим, у меня есть объект Car, который также имеет член Engine, и я хочу проверить свойства объекта, вызывая некоторые методы на Car и некоторые методы на Engine.Чтобы получить информацию в явном виде, я мог бы сделать

cout << "my car has " << mycar.GetEngine().NCylinders() << " cylinders" << endl;
cout << "my car has " << mycar.NWheels() << " wheels" << endl;

, все эти вызовы имеют форму mycar.<some method call chain here>.(Вы также можете предположить, что все они имеют совместимые типы возвращаемых данных).Как мне получить список функторов, чтобы я мог передать экземпляр Car и он будет соответствующим образом выполнять вызовы .?

Я нашел решение, использующее <tr1/functional> с использованием вложенных привязок.

#include <iostream>
#include <tr1/functional>
#include <map>

using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;

struct Engine{
    int NCylinders() const {return 12;}
};

struct Car{
    int    NWheels() const {return 4;}
    Engine GetEngine() const {return myEngine;}
private:
    Engine myEngine;
};

int main(){   
    Car mycar;

    map<string,function<double (const Car&)> > carinfos;
    carinfos["cylinders"]   = bind(&Engine::NCylinders,bind(&Car::GetEngine,_1));
    carinfos["wheels"]      = bind(&Car::NWheels,_1);

    map<string,function<double (const Car&)> >::const_iterator info = carinfos.begin();
    for(;info!=carinfos.end();++info){
        cout << "my car has: " << (info->second)(mycar) << " " << info->first << endl;
    }

    return 0;
}

, который хорошо выводит:

my car has: 12 cylinders
my car has: 4 wheels

Но вложенные связки могут стать уродливыми с более длинными цепочками или методами в середине, которые должны иметь фиксированные аргументы, и мне было интересно, могут ли бытьРешение, использующее лямбда-выражения, которое может привести к чему-то вроде

 //pseudocode
 carinfos["cylinders"]   = (_1.GetEngine().NCylinder());
 carinfos["wheels"]   = (_1.GetNWheel());

Edit:

@ KennyTM и @Kerrek SB, предоставило отличные ответы, используя новые лямбда-выражения C ++ 11.Я пока не могу использовать C ++ 11, поэтому я был бы признателен за решения аналогичной краткости, использующие C ++ 03

1 Ответ

8 голосов
/ 03 декабря 2011

Следующее, используя лямбды, а не связки, выглядит не слишком ужасно:

typedef std::map<std::string, std::function<int(Car const &)>> visitor;

int main()
{
  visitor v;
  v["wheels"]    = [](Car const & c) -> int { return c.NWheels(); };
  v["cylinders"] = [](Car const & c) -> int { return c.GetEngine().NCylinders(); };

  Car c;

  for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
  {
    std::cout << "My car has " << it->second(c) << " " << it->first << ".\n";
  }
}

Цикл может быть заключен в функцию visit(c, v);.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...