Let’s say I have a Car object which also has an Engine member, and I want to inspect the properties of the object, calling some methods on Car and some methods in Engine. To get te info explicitly I could do
cout << "my car has " << mycar.GetEngine().NCylinders() << " cylinders" << endl;
cout << "my car has " << mycar.NWheels() << " wheels" << endl;
all these calls are of the form mycar.<some method call chain here>. (you can also assume that they all have a compatible return types). How can I have a list of functors, so that I can pass an Car instance and it will execute the calls accordingly.?
I have come up with a solution using <tr1/functional> using nested binds.
#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;
}
which outputs nicely:
my car has: 12 cylinders
my car has: 4 wheels
But the nested binds can get ugly with longer chains or methods in the middle that have to have fixed arguments and I was wondering if there may be a solution using lambda expressions which could result in something like
//pseudocode
carinfos["cylinders"] = (_1.GetEngine().NCylinder());
carinfos["wheels"] = (_1.GetNWheel());
Edit:
@KennyTM and @Kerrek SB have provided excellent answers using the new C++11 lambda expressions. I cannot yet use C++11, so I would appreciate solutions of similar conciseness using C++03
The following, using lambdas rather than binds, doesn’t look too awful:
The loop could be wrapped up in a
visit(c, v);function.