首頁 > 軟體

C++11 std::function和std::bind 的使用範例詳解

2023-03-19 06:03:38

概述

C++11中的std::functionstd::bind是函數物件的重要組成部分,它們可以用於將函數和引數繫結在一起,形成一個可呼叫的物件。
std::function可以儲存任意可呼叫物件,包括函數指標、函數物件、lambda表示式等,而std::bind則可以將函數和引數繫結在一起,形成一個新的可呼叫物件。它們的使用可以大大簡化程式碼,提高程式碼的可讀性和可維護性。

可呼叫物件

C++中有如下幾種可呼叫物件,函數、函數指標、lambda表示式、bind物件、函數物件
其中,lambda表示式和bind物件是C++11標準中提出的(bind機制並不是新標準中首次提出,而是對舊版本中bind1st和bind2st的合併)。

std::function

std::function是一個可呼叫物件包裝器,是一個類別範本,可以容納除了類成員函數指標之外的所有可呼叫物件,它可以用統一的方式處理常式、函數物件、函數指標,並允許儲存和延遲它們的執行。
使用std::function可以實現回撥函數、事件處理等功能。

std::function函數原型

#include <functional>
template<class R, class... Args>
class function<R(Args...)>;
//其中,R 表示返回值型別,Args... 表示引數型別列表。
//例如,function<int(float, double)> 表示一個返回值為 int,接受一個 float 和一個 double 型別引數的函數物件。

std::function的主要作用

  • 對C++中各種可呼叫實體(普通函數、Lambda表示式、函數指標、以及其它函數物件等)的封裝,形成一個新的可呼叫的std::function物件,簡化呼叫;
  • 對C++中現有的可呼叫實體的一種型別安全的包裹(如:函數指標這類可呼叫實體,是型別不安全的)。
  • 將函數作為引數傳遞給其他函數;
  • 將函數作為返回值返回;
  • 將函數物件作為引數傳遞給其他函數;
  • 將函數物件作為返回值返回。
//例如,定義一個返回值為int,引數為兩個int的函數物件: 
std::function<int(int, int)>func; 

//可以將一個函數指標或lambda表示式賦值給函數物件: 
int add(int a, int b) { return a +b; } 
func = add; // 函數指標賦值 
func = [](int a, int b) { return a + b; };// lambda表示式賦值 

//呼叫函數物件可以使用operator(),例如:
int result = func(1, 2); // 呼叫add函數,返回3

std::function的優缺點

  • 優點:

可以方便地實現回撥函數、事件處理等功能,同時也可以用於實現函數物件的封裝和傳遞。

  • 缺點:

它的使用會帶來一定的效能開銷,因為它需要在執行時進行型別檢查和動態分配記憶體。
此外,如果使用不當,也容易引起記憶體漏失和物件生命週期管理的問題。

std::bind

std::function是一個可呼叫物件包裝器,是一個類別範本,可以容納除了類成員函數指標之外的所有可呼叫物件,它可以用統一的方式處理常式、函數物件、函數指標,並允許儲存和延遲它們的執行。

std::bind函數原型

template<class F, class... Args> 
/unspecified/ bind(F&& f, Args&&... args);
//其中,F是要繫結的函數物件,Args是要繫結的引數。返回值是一個新的可呼叫物件,可以直接呼叫或者儲存起來後再呼叫。

std::bind的主要作用

  • 將可呼叫物件和其引數繫結成一個仿函數;
  • 只繫結部分引數,減少可呼叫物件傳入的引數。
  • 繫結函數物件的引數,生成一個新的可呼叫物件,可以方便地將函數物件作為引數傳遞給其它函數。
  • 可以將成員函數繫結到物件上,生成一個新的可呼叫物件,方便地呼叫成員函數。
  • 可以將成員函數繫結到物件指標上,生成一個新的可呼叫物件,方便地呼叫成員函數。
  • 可以將成員函數繫結到物件參照上,生成一個新的可呼叫物件,方便地呼叫成員函數。
  • 可以將函數物件繫結到函數指標上,生成一個新的可呼叫物件,方便地呼叫函數物件。
  • 可以將函數物件繫結到函數參照上,生成一個新的可呼叫物件,方便地呼叫函數物件。
  • 可以將函數物件繫結到std::function物件上,生成一個新的可呼叫物件,方便地呼叫函數物件。

例如,我們有一個函數物件:
void foo(int a, int b, int c) { std::cout << a << " " << b << " " << c << std::endl; }
我們可以使用std::bind將它繫結到一些引數上:
auto f = std::bind(foo, 1, 2, 3);
這裡,f是一個新的可呼叫物件,它繫結了foo函數和引數1、2、3。我們可以像呼叫原始函數物件一樣呼叫它:
f(); // 輸出:1 2 3
我們也可以只繫結部分引數:
auto g = std::bind(foo, 1, std::placeholders::_1, 3);
這裡,std::placeholders::_1表示預留位置,它表示在呼叫g時,第二個引數會被傳遞給foo函數。我們可以這樣呼叫g:
g(2); // 輸出:1 2 3
這就是std::bind的基本用法。它可以方便地將函數物件和引數繫結在一起,生成一個新的可呼叫物件。

std::bind的優缺點

優點:

可以方便地實現函數物件的複用和引數的延遲繫結,從而提高程式碼的可讀性和可維護性。

缺點:

可能會導致程式碼的複雜性增加,特別是當引數較多時,需要謹慎使用。

程式碼範例

#pragma once

#include <iostream>
#include <functional>
class A {
public:
 bool TESTA(int, char*, int) { /* implementation */ }
};

class B {
public:
 bool TESTB(std::function<bool(int, char*, int)> func) { /* implementation */ }
};

int main() {
 A objA;
 B objB;
 auto lambda = [](int a, char* b, int c) { /* implementation */ };
 objB.TESTB(lambda);
 objB.TESTB(std::bind(&A::TESTA, &objA, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
 return 0;
}

總結

  • 預繫結的引數是以值傳遞的形式,不預繫結的引數要用std::placeholders(預留位置)的形式佔位,從_1開始,依次遞增,是以參照傳遞的形式;
  • std::placeholders表示新的可呼叫物件的第幾個引數,而且與原函數的該預留位置所在位置的進行匹配;
  • bind繫結類成員函數時,第一個參數列示物件的成員函數的指標,第二個參數列示物件的地址,這是因為物件的成員函數需要有this指標。並且編譯器不會將物件的成員函數隱式轉換成函數指標,需要通過&手動轉換;
  • std::bind的返回值是可呼叫實體,可以直接賦給std::function。

到此這篇關於C++11 std::function和std::bind 的使用的文章就介紹到這了,更多相關C++11 std::function和std::bind內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com