C++ 獲取指定的重載函數地址

来源:https://www.cnblogs.com/mkckr0/archive/2022/06/07/16353596.html
-Advertisement-
Play Games

剛剛看到一篇博客,說 stdbind 無法綁定正確的重載函數。這裡的問題並不是 stdbind 能力不足,而是將函數名傳遞給 std::bind 時編譯器無法取到這個函數的地址(也就是符號,編譯器會先解析成符號,鏈接器再替換為地址),因為有多個重載函數都是這個名字。核心問題是無法通過函數名取到想要的 ...


剛剛看到一篇博客,說 std::bind 無法綁定正確的重載函數。這裡的問題並不是 std::bind 能力不足,而是將函數名傳遞給 std::bind 時編譯器無法取到這個函數的地址(也就是符號,編譯器會先解析成符號,鏈接器再替換為地址),因為有多個重載函數都是這個名字。核心問題是無法通過函數名取到想要的重載函數地址。就像下麵的代碼無法編譯通過:

#include <iostream>

void f()
{
    std::cout << "f 1" << std::endl;
}

void f(int x)
{
    std::cout << "f 2 " << x << std::endl;
}

int main()
{
    auto p = &f;
}

編譯錯誤:

/home/abc/cpplearn/overload_func.cpp: In function ‘int main()’:
/home/abc/cpplearn/overload_func.cpp:15:15: error: unable to deduce ‘auto’ from ‘& f’
   15 |     auto p = &f;
      |               ^
/home/abc/cpplearn/overload_func.cpp:15:15: note:   couldn’t deduce template parameter ‘auto’

有沒有什麼比較完美的解決辦法呢?我覺得一定有,因為 C 語言沒有函數重載,函數地址作為實參也是常規操作。相比之下,C++ 引入了函數重載,卻無法取到函數地址,這就很尷尬。C++ 設計者肯定也想到了這個問題。

於是查閱了 cppreference.com,看到了 Address of an overloaded function。函數名的重載解析除了發生在函數調用的時候,也會發生在以下 7 種語境:

# Context Target
1 initializer in a declaration of an object or reference the object or reference being initialized
2 on the right-hand-side of an assignment expression the left-hand side of the assignment
3 as a function call argument the function parameter
4 as a user-defined operator argument the operator parameter
5 the return statement the return type of a function
6 explicit cast or static_cast argument the target type of a cast
7 non-type template argument the type of the template parameter

當函數名存在於這 7 種語境時,會發生重載解析,並且會選擇與 Target 類型匹配的那個重載函數。這裡就不一一考察這 7 種語境了,有興趣可以自己查閱 cppreference.com。這裡重點考察第 3 種和第 6 種。

先看第 3 種語境。當函數名作為函數調用的實參時,重載解析會選擇和形參類型相匹配的版本。也就是說,下麵的代碼會如期運行:

#include <iostream>

void f()
{
    std::cout << "f 1" << std::endl;
}

void f(int x)
{
    std::cout << "f 2 " << x << std::endl;
}

void call(void p(int)) {
    p(1);
}

int main()
{
    call(f);
}

這段代碼輸出:

f 2 1

回到最初的問題,std::bind 也是函數,為什麼無法正常編譯呢?直接分析下麵代碼的編譯錯誤信息:

#include <iostream>
#include <functional>

void f()
{
    std::cout << "f 1" << std::endl;
}

void f(int x)
{
    std::cout << "f 2 " << x << std::endl;
}

int main()
{
    auto new_func = std::bind(f, std::placeholders::_1);
    new_func(66);
}

編譯錯誤:

/home/abc/cpplearn/overload_func.cpp: In function ‘int main()’:
/home/abc/cpplearn/overload_func.cpp:16:30: error: no matching function for call to ‘bind(<unresolved overloaded function type>, const std::_Placeholder<1>&)’
   16 |     auto new_func = std::bind(f, std::placeholders::_1);
      |                     ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~

可以看到,std::bind 準確地說是一個函數模板。它要根據其參數進行模板實參推導,再替換模板形參進行實例化(Instantiation),產生和普通函數類似的彙編代碼。std::bind 進行實例化的時候,函數 f 還沒有進行重載解析,其類型為<unresolved overloaded function type>。std::bind 無法進行實例化。怎樣修改可以解決這個問題呢?

可以利用第 6 個語境,也就是顯示轉換或 static_cast。重載解析會選擇與它們的目標類型相匹配的版本。下麵的代碼會如期運行:

#include <iostream>
#include <functional>

void f()
{
    std::cout << "f 1" << std::endl;
}

void f(int x)
{
    std::cout << "f 2 " << x << std::endl;
}

int main()
{
    auto new_func = std::bind((void(*)(int))f, std::placeholders::_1);
    new_func(66);
}

這段代碼輸出:

f 2 66

還有一種更加巧妙的辦法,依然是利用第 3 種語境。既然 std::bind 的第一個模板實參的推導,和 f 的重載解析相矛盾。為什麼不直接解決這個矛盾,將第一個模板實參改為顯示指定?來看下麵的代碼:

#include <iostream>
#include <functional>

void f()
{
    std::cout << "f 1" << std::endl;
}

void f(int x)
{
    std::cout << "f 2 " << x << std::endl;
}

int main()
{
    auto new_func = std::bind<void(int)>(f, std::placeholders::_1);
    new_func(66);
}

這段代碼如期輸出:

f 2 66

本文來自博客園,作者:mkckr0,轉載請註明原文鏈接:https://www.cnblogs.com/mkckr0/p/16353596.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 隨著電子產品的普遍應用,AR技術也開始廣泛普及,在游戲、電商、家裝等領域都有涉及。比如,在室內設計時,我們可以通過AR技術在實際場景中進行虛擬軟裝的搭配,運用華為AR Engine運動跟蹤能力在實際應用中實時輸出室內環境的三維坐標信息,確定現實室內環境和虛擬軟裝之間的變換關係,從而穩定精準的實現軟裝 ...
  • 近年來,以機器學習為代表的人工智慧技術(以下簡稱AI技術)蓬勃發展。新演算法層出不窮,開發出的圖像識別、自然語言、活體檢測等能力令智能化的未來生活不再遙不可及。同時,這些AI技術正持續演化和發展,數據和算力的限制也在被不斷突破。依托層出不窮的新技術和新產品,交通出行、購物快遞、金融理財等各類與用戶生活 ...
  • Vue Echare 圖表 的基本使用 Apache ECharts 一個基於 JavaScript 的開源可視化圖表庫 npm install echarts vue-echartsnpm i -D @vue/composition-api 在main.js 當中(全局引用) import ech ...
  • 今天,分享一個實際業務中能夠用得上的動畫技巧。 巧用逐幀動畫,配合補間動畫實現一個無限迴圈的輪播效果,像是這樣: 看到上述示意圖,有同學不禁會發問,這不是個非常簡單的位移動畫麽? 我們來簡單分析分析,從錶面上看,確實好像只有元素的 transform: translate() 在位移,但是註意,這裡 ...
  • 前端周刊:2022-10 期 前端開發 現在 vue3+vite2 成熟了嗎,可以用在生產環境嗎? Vue3 確實還是有問題 百度統計支持單頁應用啦 單頁應用設置 首個徹底解決緩存和資料庫一致性問題的方案 業務開發中能遇到的問題多數都是工程問題而不是技術問題,前後端都適用 微信公眾號/小程式獲取當前 ...
  • 一、ThreadLocal原理分析 1、概念 ThreadLocal類並不是用來解決多線程環境下的共用變數問題,而是用來提供線程內部的共用變數。在多線程環境 下,可以保證各個線程之間的變數互相隔離、相互獨立。 2、核心原理 即:實際上是ThreadLocal的靜態內部類ThreadLocalMap為 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • """python的拆包和封包之 *號在函數形參和實參的區別1. 在函數形參定義時添加*就是封包過程,封包預設是以元組形式進行封包2. 在函數實參調用過程添加*就是拆包過程,拆包過程中會報列表或者元組拆成單個元素"""subject = ["math", "chinese", 'english', ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...