c++11新增了std::function、std::bind、lambda表達式等封裝使函數調用更加方便。ios
講std::function前首先須要瞭解下什麼是可調用對象c++
知足如下條件之一就可稱爲可調用對象:編程
而std::function就是上面這種可調用對象的封裝器,能夠把std::function看作一個函數對象,用於表示函數這個抽象概念。std::function的實例能夠存儲、複製和調用任何可調用對象,存儲的可調用對象稱爲std::function的目標,若std::function不含目標,則稱它爲空,調用空的std::function的目標會拋出std::bad_function_call異常。函數
使用參考以下實例代碼:優化
std::function<void(int)> f; // 這裏表示function的對象f的參數是int,返回值是void
#include <functional>
#include <iostream>
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_ + i << '\n'; }
int num_;
};
void print_num(int i) { std::cout << i << '\n'; }
struct PrintNum {
void operator()(int i) const { std::cout << i << '\n'; }
};
int main() {
// 存儲自由函數
std::function<void(int)> f_display = print_num;
f_display(-9);
// 存儲 lambda
std::function<void()> f_display_42 = []() { print_num(42); };
f_display_42();
// 存儲到 std::bind 調用的結果
std::function<void()> f_display_31337 = std::bind(print_num, 31337);
f_display_31337();
// 存儲到成員函數的調用
std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
const Foo foo(314159);
f_add_display(foo, 1);
f_add_display(314159, 1);
// 存儲到數據成員訪問器的調用
std::function<int(Foo const&)> f_num = &Foo::num_;
std::cout << "num_: " << f_num(foo) << '\n';
// 存儲到成員函數及對象的調用
using std::placeholders::_1;
std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
f_add_display2(2);
// 存儲到成員函數和對象指針的調用
std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
f_add_display3(3);
// 存儲到函數對象的調用
std::function<void(int)> f_display_obj = PrintNum();
f_display_obj(18);
}複製代碼
從上面能夠看到std::function的使用方法,當給std::function填入合適的參數表和返回值後,它就變成了能夠容納全部這一類調用方式的函數封裝器。std::function還能夠用做回調函數,或者在C++裏若是須要使用回調那就必定要使用std::function,特別方便,這方面的使用方式你們能夠讀下我以前寫的關於線程池和定時器相關的文章。this
使用std::bind能夠將可調用對象和參數一塊兒綁定,綁定後的結果使用std::function進行保存,並延遲調用到任何咱們須要的時候。spa
std::bind一般有兩大做用:.net
具體示例:線程
#include <functional>
#include <iostream>
#include <memory>
void f(int n1, int n2, int n3, const int& n4, int n5) {
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << std::endl;
}
int g(int n1) { return n1; }
struct Foo {
void print_sum(int n1, int n2) { std::cout << n1 + n2 << std::endl; }
int data = 10;
};
int main() {
using namespace std::placeholders; // 針對 _1, _2, _3...
// 演示參數重排序和按引用傳遞
int n = 7;
// ( _1 與 _2 來自 std::placeholders ,並表示未來會傳遞給 f1 的參數)
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 爲 _1 所綁定, 2 爲 _2 所綁定,不使用 1001
// 進行到 f(2, 42, 1, n, 7) 的調用
// 嵌套 bind 子表達式共享佔位符
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12); // 進行到 f(12, g(12), 12, 4, 5); 的調用
// 綁定指向成員函數指針
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
// 綁定指向數據成員指針
auto f4 = std::bind(&Foo::data, _1);
std::cout << f4(foo) << std::endl;
// 智能指針亦能用於調用被引用對象的成員
std::cout << f4(std::make_shared<Foo>(foo)) << std::endl;
}複製代碼
lambda表達式能夠說是c++11引用的最重要的特性之一,它定義了一個匿名函數,能夠捕獲必定範圍的變量在函數內部使用,通常有以下語法形式:指針
auto func = [capture] (params) opt -> ret { func_body; };複製代碼
其中func是能夠看成lambda表達式的名字,做爲一個函數使用,capture是捕獲列表,params是參數表,opt是函數選項(mutable之類), ret是返回值類型,func_body是函數體。
一個完整的lambda表達式:
auto func1 = [](int a) -> int { return a + 1; };
auto func2 = [](int a) { return a + 2; };
cout << func1(1) << " " << func2(2) << endl;複製代碼
如上代碼,不少時候lambda表達式返回值是很明顯的,c++11容許省略表達式的返回值定義。
lambda表達式容許捕獲必定範圍內的變量:
lambda表達式示例代碼:
int a = 0;
auto f1 = [=](){ return a; }; // 值捕獲a
cout << f1() << endl;
auto f2 = [=]() { return a++; }; // 修改按值捕獲的外部變量,error
auto f3 = [=]() mutable { return a++; };複製代碼
代碼中的f2是編譯不過的,由於咱們修改了按值捕獲的外部變量,其實lambda表達式就至關因而一個仿函數,仿函數是一個有operator()成員函數的類對象,這個operator()默認是const的,因此不能修改爲員變量,而加了mutable,就是去掉const屬性。
還可使用lambda表達式自定義stl的規則,例如自定義sort排序規則:
struct A {
int a;
int b;
};
int main() {
vector<A> vec;
std::sort(vec.begin(), vec.end(), [](const A &left, const A &right) { return left.a < right.a; });
}複製代碼
std::function和std::bind使得咱們平時編程過程當中封裝函數更加的方便,而lambda表達式將這種方便發揮到了極致,能夠在須要的時間就地定義匿名函數,再也不須要定義類或者函數等,在自定義STL規則時候也很是方便,讓代碼更簡潔,更靈活,提升開發效率。
zh.cppreference.com/w/cpp/utili…
zh.cppreference.com/w/cpp/utili…
zh.cppreference.com/w/cpp/langu…
zh.cppreference.com/w/cpp/named…
《深刻應用c++11:代碼優化與工程級應用》
《Effective Modern C++》
更多文章,請關注個人V X 公 主 號:程序喵大人,歡迎交流。