C++超詳細(xì)梳理lambda和function的使用方法
lambda表達(dá)式
lambda表達(dá)式又稱為匿名表達(dá)式,是C11提出的新語法。[]存儲(chǔ)lambda表達(dá)式要捕獲的值,()內(nèi)的參數(shù)為形參,可供外部調(diào)用傳值。lambda表達(dá)式可以直接調(diào)用
// 1 匿名調(diào)用
[](string name)
{
cout << "this is anonymous" << endl;
cout << "hello " << name << endl;
}("zack");
上述代碼定義了一個(gè)匿名函數(shù)后直接調(diào)用。我們可以通過auto初始化一個(gè)變量存儲(chǔ)lambda表達(dá)式
// 2 通過auto賦值
auto fname = [](string name)
{
cout << "this is auto " << endl;
cout << "hello " << name << endl;
};
fname("Rolin");通過auto定義fname,然后存儲(chǔ)了lambda表達(dá)式,之后調(diào)用fname即可。也可以通過函數(shù)指針的方式接受lambda表達(dá)式
typedef void (*P_NameFunc)(string name);
// 3 函數(shù)指針
P_NameFunc fname2 = [](string name)
{
cout << "this is P_NameFunc " << endl;
cout << "hello " << name << endl;
};
fname2("Vivo");P_NameFunc定義了fname2函數(shù)指針接受了lambda表達(dá)式。也可以通過function對(duì)象接受lambda表達(dá)式,function類是C11新增的語法。
// 4 function
function<void(string)> funcName;
funcName = [](string name)
{
cout << "this is function " << endl;
cout << "hello " << name << endl;
};
funcName("Uncle Wang");用一個(gè)function對(duì)象接受了lambda表達(dá)式,同樣可以調(diào)用該function對(duì)象funcName達(dá)到調(diào)用lambda的效果。
談?wù)刲ambda的捕獲
1 值捕獲
int age = 33;
string name = "zack";
int score = 100;
string job = "softengineer";
//值捕獲
[age, name](string name_)
{
cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl;
}("Novia");
上述lambda表達(dá)式捕獲了age和name,是以值的方式來捕獲的。所以無法在lambda表達(dá)式內(nèi)部修改age和name的值,如果修改age和name,編譯器會(huì)報(bào)錯(cuò),提示無法修改const常量,因?yàn)閍ge和name是以值的方式被捕獲的。
2 引用捕獲
int age = 33;
string name = "zack";
int score = 100;
string job = "softengineer";
[&age, &name](string name_)
{
cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl;
name = "Xiao Li";
age = 18;
}("Novia");
[]里age和name前邊添加了&,此時(shí)age和name是以引用方式捕獲的。所以可以在lambda表達(dá)式中修改age和name的值。
C++的lambda表達(dá)式雖然可以捕獲局部變量的引用,達(dá)到類似閉包的效果,但不是真的閉包,golang和python等語言通過閉包捕獲局部變量后可以增加局部變量的聲明周期,C++無法做到這一點(diǎn),所以下面的調(diào)用會(huì)出現(xiàn)崩潰。
vector<function<void(string)>> vec_Funcs;
void use_lambda2()
{
int age = 33;
string name = "zack";
int score = 100;
string job = "softengineer";
vec_Funcs.push_back([age, name](string name_)
{ cout << "this is value catch " << endl;
cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl; });
//危險(xiǎn),不要捕獲局部變量的引用
vec_Funcs.push_back([&age, &name](string name_)
{ cout << "this is referenc catch" << endl;
cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl; });
}
void use_lambda3()
{
for (auto f : vec_Funcs)
{
f("zack");
}
}
int main(){
use_lambda2();
use_lambda3();
}use_lambda2中將lambda表達(dá)式存儲(chǔ)在function類型的vector里,當(dāng)use_lambda2結(jié)束后,里邊的局部變量都被釋放了,而vector中的lambda表達(dá)式還存儲(chǔ)著局部變量的引用,在調(diào)用use_lambda3時(shí)調(diào)用lambda表達(dá)式,此時(shí)訪問局部變量已經(jīng)被釋放了,所以導(dǎo)致程序崩潰。
3 全部用值捕獲,name用引用捕獲
int age = 33;
string name = "zack";
int score = 100;
string job = "softengineer";
[=, &name]()
{
cout << "age is " << age << " name is " << name << " score is " << score << " job is " << job << endl;
name = "Cui Hua";
}();
通過=表示所有變量都以值的方式捕獲,如果希望某個(gè)變量以引用方式捕獲則單獨(dú)在這個(gè)變量前加&。
4 全部用引用捕獲,只有name用值捕獲
int age = 33;
string name = "zack";
int score = 100;
string job = "softengineer";
[&, name]()
{
cout << "age is " << age << " name is " << name << " score is " << score << " job is " << job << endl;
}();
通過&方式表示所有變量都已引用方式捕獲,如果希望某個(gè)變量以值方式捕獲則單獨(dú)在這個(gè)變量前加=。
萬能的function
我們可以用function存儲(chǔ)形參和返回值相同的一類函數(shù)指針,可調(diào)用對(duì)象,lambda表達(dá)式等。
void use_function()
{
list<function<void(string)>> list_Funcs;
//存儲(chǔ)函數(shù)對(duì)象
list_Funcs.push_back(FuncObj());
//存儲(chǔ)lambda表達(dá)式
list_Funcs.push_back([](string str)
{ cout << "this is lambda call " << str << endl; });
//存儲(chǔ)全局函數(shù)
list_Funcs.push_back(globalFun);
for (const auto &f : list_Funcs)
{
f("hello zack");
}
}
bind操作
C11同樣提供了bind操作,將原函數(shù)的幾個(gè)參數(shù)通過bind綁定傳值,返回一個(gè)新的可調(diào)用對(duì)象。
//綁定全局函數(shù)
auto newfun1 = bind(globalFun2, placeholders::_1, placeholders::_2, 98, "worker");
//相當(dāng)于調(diào)用globalFun2("Lily",22, 98,"worker");
newfun1("Lily", 22);
//多傳參數(shù)沒有用,相當(dāng)于調(diào)用globalFun2("Lucy",28, 98,"worker");
newfun1("Lucy", 28, 100, "doctor");
auto newfun2 = bind(globalFun2, "zack", placeholders::_1, 100, placeholders::_2);
//相當(dāng)于調(diào)用globalFun2("zack",33,100,"engineer");
newfun2(33, "engineer");
auto newfun3 = bind(globalFun2, "zack", placeholders::_2, 100, placeholders::_1);
newfun3("coder", 33);
placeholders表示占位符,_1表示新生成函數(shù)的第一個(gè)參數(shù), _2表示新生成函數(shù)的第二個(gè)參數(shù),將這些參數(shù)傳遞給原函數(shù)達(dá)到占位的效果,原函數(shù)的其余參數(shù)通過bind綁定固定值。
接下來定義類
class BindTestClass
{
public:
BindTestClass(int num_, string name_) : num(num_), name(name_) {}
static void StaticFun(const string &str, int age);
void MemberFun(const string &job, int score);
public:
int num;
string name;
};
實(shí)現(xiàn)靜態(tài)函數(shù)和成員函數(shù)
void BindTestClass::StaticFun(const string &str, int age)
{
cout << "this is static function" << endl;
cout << "name is " << str << endl;
cout << "age is " << age << endl;
}
void BindTestClass::MemberFun(const string &job, int score)
{
cout << "this is member function" << endl;
cout << "name is " << name << endl;
cout << "age is " << num << endl;
cout << "job is " << job << endl;
cout << "score is " << score << endl;
}
我們通過bind綁定靜態(tài)成員函數(shù)
//綁定類的靜態(tài)成員函數(shù),加不加&都可以
// auto staticbind = bind(BindTestClass::StaticFun, placeholders::_1, 33);
auto staticbind = bind(&BindTestClass::StaticFun, placeholders::_1, 33);
staticbind("zack");
新生成的staticbind函數(shù)可以直接傳遞一個(gè)參數(shù)zack就完成了調(diào)用。接下來用bind綁定成員函數(shù)
BindTestClass bindTestClass(33, "zack");
// 綁定類的成員函數(shù),一定要傳遞對(duì)象給bind的第二個(gè)參數(shù),可以是類對(duì)象,也可以是類對(duì)象的指針
// 如果要修改類成員,必須傳遞類對(duì)象的指針
auto memberbind = bind(BindTestClass::MemberFun, &bindTestClass, placeholders::_1, placeholders::_2);
memberbind("coder", 100);
auto memberbind2 = bind(BindTestClass::MemberFun, placeholders::_3, placeholders::_1, placeholders::_2);
memberbind2("coder", 100, &bindTestClass);
//綁定類成員時(shí),對(duì)象必須取地址
auto numbind = bind(&BindTestClass::num, placeholders::_1);
std::cout << numbind(bindTestClass) << endl;
當(dāng)然也可以直接用function對(duì)象接受bind返回的結(jié)果
// function接受bind返回的函數(shù)
function<void(int, string)> funcbind = bind(globalFun2, "zack", placeholders::_1, 100, placeholders::_2);
funcbind(33, "engineer");
// function接受bind 成員函數(shù)
function<void(string, int)> funcbind2 = bind(BindTestClass::MemberFun, &bindTestClass, placeholders::_1, placeholders::_2);
funcbind2("docker", 100);
function<void(string, int, BindTestClass *)> funcbind3 = bind(BindTestClass::MemberFun, placeholders::_3, placeholders::_1, placeholders::_2);
funcbind3("driver", 100, &bindTestClass);
// function 直接接受成員函數(shù),function的模板列表里第一個(gè)參數(shù)是類對(duì)象引用
function<void(BindTestClass &, const string &, int)> functomem = BindTestClass::MemberFun;
functomem(bindTestClass, "functomem", 88);
// function 綁定類的靜態(tài)成員函數(shù)
function<void(const string &)> funbindstatic = bind(&BindTestClass::StaticFun, placeholders::_1, 33);
funbindstatic("Rolis");lambda和bind的使用就介紹到這里
到此這篇關(guān)于C++超詳細(xì)梳理lambda和function的使用方法的文章就介紹到這了,更多相關(guān)C++ lambda和function內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VC++6.0實(shí)現(xiàn)直線掃描轉(zhuǎn)換的圖文教程
這篇文章主要給大家介紹了關(guān)于VC++6.0實(shí)現(xiàn)直線掃描轉(zhuǎn)換的相關(guān)資料,文中通過圖文將實(shí)現(xiàn)的步驟一步步介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用VC++6.0具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-01-01
visual studio2019的安裝以及使用圖文步驟詳解
這篇文章主要介紹了visual studio2019的安裝以及使用圖文步驟詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
史上最貼心的 VS code C++ 環(huán)境配置超詳細(xì)教程
這篇文章主要介紹了史上最貼心的 VS code C++ 環(huán)境配置超詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02

