2011-12-03 94 views
2

比方說,我有一個Car對象,它也有一個Engine成員,我想檢查對象的屬性,呼籲Car一些方法和Engine一些方法。爲了得到TE信息明確我可以做C++ lambda表達式的方法鏈

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

+0

也許訪客模式? 「Wheel visitor,Cylinder visitor」...訪問者的實現功能可以是lambda。 –

+0

是的,這將工作,但我不能改變類的接口。 – luksen

+0

在你的僞代碼中,最後一行應該有「nwheel」,而不是「cylinders」,對吧? – dasblinkenlight

回答

7

下欣賞類似簡潔的解決方案,使用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);函數中。

+0

我想這是C++ 11的規範答案。 – luksen

+1

+1在這個特定的lambda表達式中,包含一個'return'表達式並且沒有其他代碼,返回類型是可選的,所以它可以拼寫爲:'[](Car const&c){return c .NWheels(); }' –