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

Tags: