用于方法链的c++ lambda表达式

C++ lambda expression for method chains

本文关键字:lambda 表达式 c++ 方法 用于      更新时间:2023-10-16

假设我有一个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

但是嵌套绑定可以变得丑陋与较长的链或方法在中间,必须有固定的参数,我想知道是否可能有一个解决方案使用lambda表达式可能导致类似的东西

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

@KennyTM和@Kerrek SB使用新的c++ 11 lambda表达式提供了出色的答案。我还不能使用c++ 11,所以我很欣赏使用c++ 03

的类似简洁的解决方案。

下面的代码,使用lambda而不是绑定,看起来并不太糟糕:

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);函数封装。