VC的function類說明 -- 繼續

来源:https://www.cnblogs.com/albizzia/archive/2018/05/23/9074913.html
-Advertisement-
Play Games

我在之前的隨筆中介紹了function如何保存參數,如何實現調用相關知識。對於一個函數對象或者函數指針來說,應該很容易理解。不過對於如何在function中保存類的成員函數,這個還是值得一說的。 還是按照之前的方式,通過boost的type_index,我們可以比較容易的知道function的父類是 ...


我在之前的隨筆中介紹了function如何保存參數,如何實現調用相關知識。對於一個函數對象或者函數指針來說,應該很容易理解。不過對於如何在function中保存類的成員函數,這個還是值得一說的。

還是按照之前的方式,通過boost的type_index,我們可以比較容易的知道function的父類是_Func_class。

這裡先看一段代碼:

    template<class _Fx,
        class _Inv_res = typename _Mybase::template _Result_of_invoking_t<_Fx&>,
        class = typename _Mybase::template _Enable_if_returnable_t<_Inv_res> >
        function(_Fx _Func)
        {    // construct wrapper holding copy of _Func
        this->_Reset(_STD move(_Func));
        }

這個是function的一個構造函數,其中的_Inv_res是這個構造函數能夠使用的條件,條件的內容是_Mybase::_Result_of_invoking_t<_Fx&>可以獲得一個類型。

現在我們查看_Result_of_invoking_t定義的位置:

protected:
    template<class _Fx>
        using _Result_of_invoking_t = result_of_t<_Fx(_Types...)>;

上面是在_Func_class中的定義。下麵給出類result_of_t的定義。

template<class _Ty>
    using result_of_t = typename result_of<_Ty>::type;

template<class _Void,
    class... _Types>
    struct _Result_of
    {    // selected when _Fty isn't callable with _Args
    };

template<class... _Types>
    struct _Result_of<
        void_t<
            _Unique_tag_result_of,    // TRANSITION, C1XX
            decltype(_STD invoke(_STD declval<_Types>()...))>,
        _Types...>
    {    // selected when _Fty is callable with _Args
    typedef decltype(_STD invoke(_STD declval<_Types>()...)) type;
    };

template<class _Fty>
    struct result_of
    {    // explain usage
    static_assert(_Always_false<_Fty>::value,
        "result_of<CallableType> is invalid; use "
        "result_of<CallableType(zero or more argument types)> instead.");
    };

#define _RESULT_OF(CALL_OPT, X1, X2) \
template<class _Fty, \
    class... _Args> \
    struct result_of<_Fty CALL_OPT (_Args...)> \
        : _Result_of<void, _Fty, _Args...> \
    {    /* template to determine result of call operation */ \
    };

由上述代碼可知,result_of的實現依賴於std::invoke函數的實現。

我們再查看一下function函數的調用路徑:

    _Ret operator()(_Types... _Args) const
        {    // call through stored object
        if (_Empty())
            _Xbad_function_call();
        return (_Getimpl()->_Do_call(_STD forward<_Types>(_Args)...));
        }

上述是_Func_class的調用函數。

    virtual _Rx _Do_call(_Types&&... _Args)
        {    // call wrapped function
        return (_Invoke_ret(_Forced<_Rx>(), _Callee(),
            _STD forward<_Types>(_Args)...));
        }

這個是_Func_impl的調用,也就是上面_Getimpl()->_Do_call的實現函數。下麵,我們再查看一下_Invoke_ret的實現:

template<class _Cv_void,
    class... _Valtys> inline
    void _Invoke_ret(_Forced<_Cv_void, true>, _Valtys&&... _Vals)
    {    // INVOKE, "implicitly" converted to void
    _STD invoke(_STD forward<_Valtys>(_Vals)...);
    }

template<class _Rx,
    class... _Valtys> inline
    _Rx _Invoke_ret(_Forced<_Rx, false>, _Valtys&&... _Vals)
    {    // INVOKE, implicitly converted to _Rx
    return (_STD invoke(_STD forward<_Valtys>(_Vals)...));
    }

template<class... _Valtys> inline
    auto _Invoke_ret(_Forced<_Unforced, false>, _Valtys&&... _Vals)
    -> decltype(_STD invoke(_STD forward<_Valtys>(_Vals)...))
    {    // INVOKE, unchanged
    return (_STD invoke(_STD forward<_Valtys>(_Vals)...));
    }

由上面代碼可見,無一例外,function的判斷和實現都依賴於std::invoke的實現。那麼std::invoke是如何實現的呢?

template<class _Callable,
    class... _Types> inline
    auto invoke(_Callable&& _Obj, _Types&&... _Args)
    -> decltype(_Invoker<_Callable, _Types...>::_Call(
        _STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))
    {    // INVOKE a callable object
    return (_Invoker<_Callable, _Types...>::_Call(
        _STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...));
    }

在VS2015中,invoke的實現代碼如上,可見invoke的實現依賴於_Invoker類。下麵,我們查看一下_Invoker的實現:

template<class _Callable,
    class... _Types>
    struct _Invoker;

template<class _Callable>
    struct _Invoker<_Callable>
        : _Invoker_functor
    {    // zero arguments
    };

template<class _Callable,
    class _Ty1,
    class... _Types2>
    struct _Invoker<_Callable, _Ty1, _Types2...>
        : _Invoker1<_Callable, _Ty1>
    {    // one or more arguments
    };

可見,我們需要繼續查看_Invoker1的實現:

template<class _Callable,
    class _Ty1,
    class _Decayed = typename decay<_Callable>::type,
    bool _Is_pmf = is_member_function_pointer<_Decayed>::value,
    bool _Is_pmd = is_member_object_pointer<_Decayed>::value>
    struct _Invoker1;

template<class _Callable,
    class _Ty1,
    class _Decayed>
    struct _Invoker1<_Callable, _Ty1, _Decayed, true, false>
        : _If<is_base_of<
            typename _Is_memfunptr<_Decayed>::_Class_type,
            typename decay<_Ty1>::type>::value,
        _Invoker_pmf_object,
        _Invoker_pmf_pointer>::type
    {    // pointer to member function
    };

template<class _Callable,
    class _Ty1,
    class _Decayed>
    struct _Invoker1<_Callable, _Ty1, _Decayed, false, true>
        : _If<is_base_of<
            typename _Is_member_object_pointer<_Decayed>::_Class_type,
            typename decay<_Ty1>::type>::value,
        _Invoker_pmd_object,
        _Invoker_pmd_pointer>::type
    {    // pointer to member data
    };

template<class _Callable,
    class _Ty1,
    class _Decayed>
    struct _Invoker1<_Callable, _Ty1, _Decayed, false, false>
        : _Invoker_functor
    {    // function object
    };

以及實現_Invoker1的底層類:

struct _Invoker_pmf_object
{    // INVOKE a pointer to member function on an object
template <class _Decayed, class _Ty1, class... _Types2>
static auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args)
->decltype((std::forward<_Ty1>(_Arg1).*_Pmf)(
    std::forward<_Types2>(_Args2)...))
    {    // INVOKE a pointer to member function on an object
        return ((_STD forward<_Ty1>(_Arg1).*_Pmf)(
            std::forward<_Types2>(_Args2)...
        ));
    }    
};

struct _Invoker_pmf_pointer
{    // INVOKE a pointer to member function on a [smart] pointer
template <class _Decayed, class _Ty1, class... _Types2>
static auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... Args2)
->decltype(((*std::forward<_Ty1>(_Arg1)).*_Pmf)(
    std::forward<_Types2>(_Arg2)...))
    {    // INVOKE a pointer to member function on a [smart] pointer
        return (((*std::forward<_Ty1>(_Arg1)).*_Pmf)(
        std::forward<_Types2>(_Arg2)...));
    }
};

struct _Invoker_pmd_object
{    // INVOKE a pointer to member data on an object
template<class _Decayed, class _Ty1>
static auto _Call(_Decayed _Pmd, _Ty1&& _Arg1)
->decltype(std::forward<_Ty1>(_Arg1).*_Pmd)
{    // INVOKE a pointer to member data on a [smart] pointer
    return (std::forward<_Ty1>(_Arg1).*_Pmd);
}
    
};

struct _Invoker_pmd_pointer
{    // INVOKE a pointer to member data on a [smart] pointer
template <class _Decayed, class _Ty1>
static auto _Call(_Decayed _Pmd, _Ty1&& _Arg1)
->decltype((*std::forward<_Ty1>(_Arg1)).*_Pmd)
{    // INVOKE a pointer to member data on a [smart] pointer
    return ((*std::forward<_Ty1>(_Arg1)).*_Pmd);
}
};

struct _Invoker_functor
{    // INVOKE a function object
template <class _Callable, class... _Types>
static auto _Call(_Callable&& _Obj, _Types&&... _Args)
->decltype(std::forward<_Callable>(_Obj)(
    std::forward<_Types>(_Args)...))
    {    // INVOKE a function object
        return (std::forward<_Callable>(_Obj)(
            std::forward<_Types>(_Args)...));
    }
};

實現的過程,主要在於:bool _Is_pmf = is_member_function_pointer<_Decayed>::valuebool _Is_pmd = is_member_object_pointer<_Decayed>::value>兩個判斷語句,通過這個來實現SFINAE的語義,從而實現針對類型的特例化。為了說明上面兩個判斷才是重點,輸入如下代碼:

class A
{
public:
    A(){}

    void printA() const
    {
        std::cout << "printA" << std::endl;
    }
};

void printB(A a)
{
    std::cout << "printB" << std::endl;
}

int main()
{
    std::_Invoker_pmf_object::_Call(&A::printA, A());
    std::_Invoker_pmf_pointer::_Call(&A::printA, &A());
    std::_Invoker_functor::_Call(printB, A());
    
    return 0;
}

查看列印結果。由於_Invoker_pmf_object_Invoker_pmf_pointer_Invoker_functor的實現本來很簡單,所以invoke調用的重點在於上述判斷語句。這裡就解釋到此,時間倉促,希望見諒。


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

-Advertisement-
Play Games
更多相關文章
  • ...
  • 安裝 概念 在redux中分為3個對象:Action、Reducer、Store Action 1. 對行為(如用戶行為)的抽象 1. Action 就是一個普通 JavaScript 對象。如: (其中type欄位是約定也是必須的) 1. 作為Reducer的參數 Reducer 1. 一個普通的 ...
  • select下拉框選中的值,用jquery大家應該都會獲取, 如果select是多選的,也這麼獲取的話,則只能獲取到第一個選項的value值,但是有一個神奇的發現,如果是: 獲取text,則可以直接列印出選中的兩個選項的文本值的相連字元串,而不是只是第一個的text......... 獲取多選框的v ...
  • 1. vue-cli 簡介 Vue-cli 是 vue的設計者,為提升開發效率而提供的一個腳手架工具,可通過vue-cli快速構造項目結構 2. vue-cli 安裝步驟 安裝npm 或 cnpm 安裝webpack、webpack-cli 建議全局安裝一次: 建議全局安裝一次: 本地安裝一次: 本 ...
  • 下午學習了設計模式里的策略模式,寫個筆記,做個總結 策略模式的UML圖為: 舉個例子: 我們每個人都想走向人生巔峰,但是怎麼走向人生巔峰呢??有三個方法:1、當總經理;2、出任CEO;3、娶白富美。正好我身邊有三個小伙伴,他們就想通過這三種策略來走向人生巔峰。。。 首先是走向人生巔峰的策略介面 然後 ...
  • Django運算表達式與Q對象/F對象 1 模型查詢 概述: 1 查詢集:表示從資料庫中獲取的對象的集合 2 查詢集可以有多個過濾器,通過 邏輯運算符連接 3 過濾器就是一個函數,基於所給的參數限制查詢的結果,類似MySQL模糊查詢中where語句 4 查詢集等同select語句 2 查詢集 特點: ...
  • Python里的變數 門牌 Python在使用變數之前無須定義它的類型,但是必須聲明以及初始化該變數。 Python中給變數賦值就是聲明,初始化變數(也就是創建一個相應數據類型的對象,而那些數據類型就是類),變數的類型是取決於其儲存的數據。(下麵代碼中的a變數,其類型類型隨著賦值的類型不同而改變) ...
  • 1、網頁打開檢查器,到達該路徑,再刷新網頁,點擊第一個“Attractions”文件,出現headers(重要)、response、cookies等信息 2、定位元素位置方法,找唯一特征: 用滑鼠右鍵定位該元素的標簽位置,找出這類信息的唯一性屬性,最後用“標簽+屬性”的方式定位該欄位信息。如定點陣圖片 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...