C++ 重載函數調用運算符 | 再探lambda,函數對象,可調用對象

文章目錄

  • 重載函數調用運算符
  • lambda
    • lambda等價于函數對象
    • lambda等價于類
  • 標準庫函數對象
  • 可調用對象與function
    • 可調用對象
    • function
      • 函數重載與function


重載函數調用運算符

函數調用運算符必須是成員函數。 一個類可以定義多個不同版本的調用運算符,互相之間應該在參數數量or類型上有所區別。如果類定義了函數調用運算符 () ,則該類的對象稱作函數對象,因為可以調用這種對象,所以我們說這些對象的行為像函數一樣。

class absInt {
public:int operator()(int val)const {return val < 0 ? -val : val;}
};

在這里插入圖片描述


lambda

lambda等價于函數對象

對于作為最后一個實參的 lambda 的表達式來說:

//根據單詞的長度對其進行排序,對于長度相同的單詞按照字母表順序排序
stable_sort (words.begin(), words.end(),[](const string &a, const string &b){return a.size () < b.size();});

其等價于下面這個類的一個未命名對象:

class ShorterString {
public:bool operator()(const string &s1, const string &s2) const{ return s1.size() < s2.size(); }
};

默認情況下,lambda 不能改變它捕獲的變量,因此類的函數調用運算符是一個 const 成員函數。

那么我們可以重寫并調用 stable_sort

stable_sort(words.begin(), words.end(), ShorterString());

lambda等價于類

  • 當一個 lambda表達式 通過引用捕獲變量時,將由程序負責確保 lambda 執行時所引用的對象確實存在。因此,編譯器可以直接使用該引用而無須在 lambda產生的類 中將其存儲為數據成員。
  • 過值捕獲的變量被拷貝到 lambda 中。因此,這種 lambda 產生的類必須為每個值捕獲的變量建立對應的數據成員,同時創建構造函數,令其使用捕獲的變量的值來初始化數據成員。

舉個例子,有這樣一個 lambda,它的作用是找到第一個長度不小于給定值的 string 對象:

//獲得第一個指向滿足條件元素的迭代器,該元素滿足 size() >= sz
auto wc = find_if(words.begin(), words.end(),[sz] (const string &a){ return a.size() >= sz;});

等價于這樣的類:

class SizeComp{size_t sz; // 該數據成員對應通過值捕獲的變量
public:SizeComp (size_t n): sz(n) {} // 該形參對應捕獲的變量// 該調用運算符的返回類型、形參和函數體都與lambda一致bool operator()(const string &s) const { return s.size()>= sz; }

由于這個類不含默認構造函數,因此想要調用它必須提供一個實參,也就起到了 值捕獲 的作用。


標準庫函數對象

在這里插入圖片描述
表示運算符的函數對象類常用來替換算法中的默認運算符。

例如,在默認情況下排序算法使用 operator< 將序列按照升序排列。如果要執行降序排列的話,我們可以傳入一個 greater 類型的對象。該類將產生一個調用運算符并負責執行待排序類型的大于運算:

// sv是一個vecotr<string>,greater<string>()是一個臨時的函數對象
sort(sv.begin(), sv.end(), greater<string>());

標準庫函數對象適用性是很寬的,甚至適用于指針:
在這里插入圖片描述
而實際上,STL 中也正是這樣做的:關聯容器使用 less<key_type> 對元素排序,因此我們可以定義一個指針的 set 或者在 map 中使用指針作為關鍵值而無須直接聲明 less


可調用對象與function

可調用對象

C++語言中有幾種可調用的對象:函數、函數指針、lambda表達式、bind創建的對象、重載了函數調用運算符的類。

和其他對象一樣,可調用的對象也有類型。例如,每個lambda有它自己唯一的(未命名)類類型;函數及函數指針的類型則由其返回值類型和實參類型決定,等等。

然而,兩個不同類型的可調用對象卻可能共享同一種調用形式(call signature)。 調用形式指明了調用返回的類型以及傳遞給調用的實參類型。一種調用形式對應一個函數類型,例如:

int(int, int)

是一個函數類型,它接受兩個 int、返回一個 int

用具體的例子來講,即:
在這里插入圖片描述
上面三個可調用對象共享一種調用形式—— int(int, int)

對于調用形式相同的可調用對象,我們可以定義一個函數表(function table)存儲他們的“指針”,對他們進行統一管理。 當程序需要執行特定的 +%/ 時,從表中查找該操作對應的可調用對象。

C++ 中,函數表很容易通過 map 實現:

// string表示 + 或 % 或 / 
// 函數指針 作為 value
map<string, int(*)(int, int)> m;
// 我們可以將 add的指針 加入到 m 中
m.insert({"+", add}); // {"+", add}是一個pair
// 但不可以將 mod 或者 divide 存入 m
m.insert({"%", mod}); // error:mod不是一個函數指針,lambda有自己的類類型 

function

在這里插入圖片描述
function 模板的運用示例:

function<int(int, int)>
// 聲明了一個function類型,表示接受兩個int、返回一個int的可調用對象

在這里插入圖片描述

// 用function<int(int, int)>表示上面的可調用對象
function<int(int, int)> f1 = add; // 函數指針
function<int(int, int)> f2 = divide(); // 函數對象類的對象
function<int(int, int)> f3 = [](ing i, int j) {return i%j}; // lambdacout << f1(4, 2) << endl; // 打印6
cout << f2(4, 2) << endl; // 打印2
cout << f3(4, 2) << endl; // 打印0

function 也可以和 map 搭配使用:

初始化:
在這里插入圖片描述
使用:
在這里插入圖片描述


函數重載與function

我們不能直接將重載函數的名字存入 function 類型的對象中:

int add(int i, int j) { return i + j; }
A add(const A&, const A&);
map<string, function<int(int, int)>> m;
m.insert( {"+", add} ); // ERROR:哪個add?

解決上述二義性問題的一條途徑是存儲函數指針而非函數名字:

int (*fp)(int, int) = add;
m.insert( {"+", fp} );

新版本標準庫中的 function 類與舊版本中的 unary_function 和 binary_function 沒有關聯。后兩個類已經被更通用的 bind 函數替代了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443735.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443735.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443735.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ 運算符重載(二) | 類型轉換運算符,二義性問題

文章目錄類型轉換運算符概念避免過度使用類型轉換函數解決上述問題的方法轉換為 bool顯式的類型轉換運算符類型轉換二義性重載函數與類型轉換結合導致的二義性重載運算符與類型轉換結合導致的二義性類型轉換運算符 概念 類型轉換運算符&#xff08;conversion operator&#…

Tomcat中JVM內存溢出及合理配置

Tomcat本身不能直接在計算機上運行&#xff0c;需要依賴于硬件基礎之上的操作系統和一個Java虛擬機。Tomcat的內存溢出本質就是JVM內存溢出&#xff0c;所以在本文開始時&#xff0c;應該先對Java JVM有關內存方面的知識進行詳細介紹。 一、Java JVM內存介紹 JVM管理兩種類型的…

俄羅斯農民乘法 | 快速乘

文章目錄概念概念 俄羅斯農民乘法經常被用于兩數相乘取模的場景&#xff0c;如果兩數相乘已經超過數據范圍&#xff0c;但取模后不會超過&#xff0c;我們就可以利用這個方法來拆位取模計算貢獻&#xff0c;保證每次運算都在數據范圍內。 A 和 B 兩數相乘的時候我們如何利用加…

Linux網絡編程 | socket選項設定 及 網絡信息API

文章目錄讀取和設置 socket 選項SO_REUSEADDRSO_RCVBUF 和 SO_SNDBUFSO_RCVLOWAT 和 SO_SNDLOWATSO_LINGER 選項網絡信息APIgethostbyname 和 gethostbyaddrgetservbyname 和 getservbyportgetaddrinfogetnameinfo讀取和設置 socket 選項 正如 fcntl 系統調用是控制文件描述符…

Linux | 高級I/O函數

文章目錄創建文件描述符的函數pipe函數dup函數、dup2函數讀取或寫入數據readv函數、writev函數零拷貝sendfile函數splice函數tee函數進程間通信——共享內存mmap函數 和 munmap函數控制文件描述符fcntl函數創建文件描述符的函數 pipe函數 不再贅述&#xff0c;詳情見我的另一…

分布式理論:CAP、BASE | 分布式存儲與一致性哈希

文章目錄分布式理論CAP定理BASE理論分布式存儲與一致性哈希簡單哈希一致性哈希虛擬節點分布式理論 CAP定理 一致性&#xff08;Consistency&#xff09;&#xff1a; 在分布式系統中的所有數據副本&#xff0c;在同一時刻是否一致&#xff08;所有節點訪問同一份最新的數據副…

Tomcat服務器性能優化

一、概述 本文檔主要介紹了Tomcat的性能調優的原理和方法。可作為公司技術人員為客戶Tomcat系統調優的技術指南&#xff0c;也可以提供給客戶的技術人員作為他們性能調優的指導手冊。 二、調優分類 由于Tomcat的運行依賴于JVM&#xff0c;從虛擬機的角度我們把Tomcat的調整分為…

分布式系統概念 | 分布式事務:2PC、3PC、本地消息表

文章目錄分布式事務2PC&#xff08;二階段提交協議&#xff09;執行流程優缺點3PC&#xff08;三階段提交協議&#xff09;執行流程優缺點本地消息表&#xff08;異步確保&#xff09;分布式事務 分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分…

數據結構算法 | 單調棧

文章目錄算法概述題目下一個更大的元素 I思路代碼下一個更大元素 II思路代碼132 模式思路代碼接雨水思路算法概述 當題目出現 「找到最近一個比其大的元素」 的字眼時&#xff0c;自然會想到 「單調棧」 。——三葉姐 單調棧以嚴格遞增or遞減的規則將無序的數列進行選擇性排序…

最長下降子序列

文章目錄題目解法DP暴搜思路代碼實現貪心二分思路代碼實現題目 給出一組數據 nums&#xff0c;求出其最長下降子序列&#xff08;子序列允許不連續&#xff09;的長度。&#xff08;類似于lc的最長遞增子序列&#xff09; 示例&#xff1a; 輸入&#xff1a; 6 // 數組元素個…

Linux 服務器程序規范、服務器日志、用戶、進程間的關系

文章目錄服務器程序規范日志rsyslogd 守護進程syslog函數openlog函數setlogmask函數closelog函數用戶進程間的關系進程組會話系統資源限制改變工作目錄和根目錄服務器程序后臺化服務器程序規范 Linux 服務器程序一般以后臺進程&#xff08;守護進程[daemon]&#xff09;形式運…

IO模型 :阻塞IO、非阻塞IO、信號驅動IO、異步IO、多路復用IO

文章目錄IO模型阻塞IO非阻塞IO信號驅動IO多路復用IO異步IOIO模型 根據各自的特性不同&#xff0c;IO模型被分為阻塞IO、非阻塞IO、信號驅動IO、異步IO、多路復用IO五類。 最主要的兩個區別就是阻塞與非阻塞&#xff0c;同步與異步。 阻塞與非阻塞 阻塞與非阻塞最主要的區別就…

Tomcat服務器集群與負載均衡實現

一、前言 在單一的服務器上執行WEB應用程序有一些重大的問題&#xff0c;當網站成功建成并開始接受大量請求時&#xff0c;單一服務器終究無法滿足需要處理的負荷量&#xff0c;所以就有點顯得有點力不從心了。另外一個常見的問題是會產生單點故障&#xff0c;如果該服務器壞掉…

Linux服務器 | 事件處理模式:Reactor模式、Proactor模式

文章目錄Reactor模式Proactor模式同步I/O模型模擬Proactor模式兩者的優缺點ReactorProactor同步I/O模型通常用于實現 Reactor 模式&#xff0c;異步I/O模型通常用于實現 Proactor 模式。&#xff08;不是絕對的&#xff0c;同步I/O也可模擬出 Proactor 模式&#xff09; React…

Linux服務器 | 服務器模型與三個模塊、兩種并發模式:半同步/半異步、領導者/追隨者

文章目錄兩種服務器模型及三個模塊C/S模型P2P模型I/O處理單元、邏輯單元、存儲單元并發同步與異步半同步/半異步模式變體&#xff1a;半同步/半反應堆模式改進&#xff1a;高效的半同步/半異步模式領導者/追隨者模式組件 &#xff1a;句柄集、線程集、事件處理器工作流程兩種服…

香農信息熵之可憐的小豬

文章目錄題目解析香農熵公式樣例具體分析代碼題目 有 n 桶液體&#xff0c;其其中 正好 有一桶含有毒藥&#xff0c;其裝的都是水。它們從外觀看起來都一樣。為了弄清楚哪只水桶含有毒藥&#xff0c;你可以喂一些豬喝&#xff0c;通過觀察豬是否會死進行判斷&#xff0c;實驗對…

字符串匹配之KMP(KnuthMorrisPratt)算法(圖解)

文章目錄最長相等前后綴next數組概念代碼實現圖解GetNext中的回溯改進代碼實現代碼復雜度分析最長相等前后綴 給出一個字符串 ababa 前綴集合&#xff1a;{a, ab, aba, abab} 后綴集合&#xff1a;{a, ba, aba, baba} 相等前后綴 即上面用同樣顏色標識出來的集合元素&#…

linux下tomcat6.0與jdk安裝詳細步驟

安裝Tomcat6.0和JDK1.6 在linux系統上安裝tomcat和jdk應該說是我學習linux知識的第一課了&#xff0c;之前只 是聽說過&#xff0c;從沒接觸過&#xff0c;但我們公司項目都是部署在linux系統上的&#xff0c;那天上司突 然給我發了幾個文檔&#xff0c;讓我看一下&#xff…

Android入門(一) | Android Studio的配置與使用

文章目錄安裝配置Android Studio使用Android Studio模擬器更改Android SDK的路徑Hello World&#xff01;安裝配置Android Studio 從這一步開始&#xff1a; 一直點 next 即可&#xff0c;直到存儲路徑的選擇上&#xff0c;可以放到非 C 盤&#xff0c;這里我放到 D 盤了&am…

Android 入門(四) | Intent 實現 Activity 切換

文章目錄Intent顯式 Intent定義兩個 xml 文件android:orientationmatch_parent 和 wrap_contentIntent函數定義兩個 Activity隱式 Intent更多隱式 Intent 的用法用隱式 Intent 打開系統瀏覽器自建 Activity 以響應打開網頁的 Intent向下一個活動傳遞數據返回數據給上一個活動In…