c++11 符號修飾與函數簽名、函數指針、匿名函數、仿函數、std::function與std::bind
一、符號修飾與函數簽名
1、符號修飾
編譯器將c++源程式碼編譯成目標文件時,用函數簽名的資訊對函數名進行改編,形成修飾名。GCC的C++符號修飾方法如下:
1)所有符號都以_z開頭
2)名字空間的名字
名字空間(或類)的名字前加上N
名字前還有一個數字,是名字的字元數。比如1C,1是C的長度。
3)函數名
與名字空間一樣,函數名前也有數字,比如4func,4是func的字元數。
4)參數
參數以E開頭
例子
N::C::func(int) 的函數簽名經過修飾為_ZN1N1C4funcEi
2、函數簽名
函數簽名組成部分:包括函數名,參數類型,參數個數和順序,以及它所在類和命名空間。
以上任何一個部分的不同,都會導致符號修飾後的名詞不同,即導致函數簽名不同,故可以區分不同的函數,在調用的時候就不會出錯。
二、函數指針
例子: int(*p)(int,int)
語句定義了一個指向函數的指針變數P,這個函數指針可以指向這麼一個函數,即返回值為int類型,且有兩個int參數的函數,指針p的類型為int(*)(int,int)。
函數指針的統一定義方式為:
函數返回類型(* 指針變數名)(函數參數列表)
簡單用法:
int func(int x); //定義一個函數
int (*p)(int x); //定義一個函數指針
p=func; //將函數func的首地址賦值給指針變數p
三、c++11中的匿名函數(lambda函數,lambda表達式)
C++11提供了對匿名函數的支援,稱為lambda函數(也成為lambda表達式),形式如下
[capture](parameters)->return-type{body}
解析:
capture
1)、[] //未定義變數,試圖在lambda函數內使用任何外部變數都是錯誤的
2)、[x,&y] //x按值捕獲,y按引用捕獲
3)、[&] //用到的任何外部變數都隱式按引用捕獲
4)、[=] //用到的任何外部變數都隱式按值捕獲
5)、[&,x] //x顯式按值捕獲,其他變數按照引用捕獲
6)、[=,&z] //z按引用捕獲,其他變數按值捕獲
parameters:存儲函數的參數,當parameters為空的時候,()可以省去
return-type:函數的返回值,如果funtion body中存在return語句,則該lambda表達式的返回類型由return語句的返回類型確定。
body:函數體
例子:
auto fun=[](int x){ return x; }
cout<<fun(1)<<endl; //輸出1
四、仿函數
本質:仿函數的本質就是類重載了一個operator(),創建一個行為類似函數的對象。
例子:
template<class T>
stuct plus:public binary_function<T,T,T>{
T operator()(const T &x,const T &y) const{return x-y;}
};
cout<<“plus=”<<plus<int>(2,1)<<endl; //輸出1
五、std::function與std::bind本質
1、std::finction
std::function是函數模板類(是一個類);std::bind是函數模板(是一個函數),其包含在#include<functional>文件中。
std::function 即把函數對象化,將函數當作一個類的對象,主要目的是期望看到更多的泛型演算法,不希望看到使用函數取操作數據的程式碼
通過std::function對C++中各種可調用實體(普通函數、lambda表達式,函數指針、以及其他的函數對象等)的封裝,形成一個新的可調用的std::function對象,讓我們不再糾結那麼的的可調用實體。
例子:
1)、std::function<int(int a)> func //聲明一個std::function對象
2)、int test(int){return a}; //普通函數
3)、auto test=[](int a)->int{return a} //匿名函數
4)、class test{ //仿函數
public:
int operator()(int a){
return a;
}
};
5)、class test{ //類成員函數&類靜態函數
public:
int tseta(int a){return a}
static int testb(int a){return a;}
};
//調用
//1、普通函數
func=test;
func(1);
//2、匿名函數
func=test
func(1);
//3、仿函數
test t;
func=t;
func(1);
//4、類成員函數
test t;
func=std::bind(&test::testa, t ,std::placeholder::_1); //std::placeholder::_1 :佔位符號
func(1);
//5、類靜態成員函數
func=test::testb;
func(1);
2、std::bind
std::bind可以看作一個通用的函數適配器,它接受一個可調用對象,生成一個新的可調用對象來適應原對象的參數列表。
作用:
1)std::bind將可調用對象和其參數綁定成一個仿函數
2)只綁定部分參數,減少可調用對象傳入的參數
例子:
//1、綁定普通函數
int test_a(int x,inty){return x+y;}
auto test_A=std::bind(test_a,_1,10); //_1:佔位符
test_A(2); //12
//2、綁定類成員函數
struct test_struct{
int test_b(int x,int y){
return x+y;
}
};
test_struct test_tt;
auto test_B=std::bind(&test_struct::test_b,&test_tt,20,30); //第一個參數為類成員函數的指針(必須顯示指定函數,編譯器不幫忙),第二個參數為類對象的地址(指明哪個對象的指針),後面兩個為函數test_b的兩個參數
test_B(); //50