最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談C++11的std::mem_fn源碼解析

 更新時(shí)間:2021年06月18日 10:35:43   作者:彼 方  
本文是基于gcc-4.9.0的源代碼進(jìn)行分析,std::mem_fn是C++11才加入標(biāo)準(zhǔn)的,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

1、源碼準(zhǔn)備

本文是基于gcc-4.9.0的源代碼進(jìn)行分析,std::mem_fn是C++11才加入標(biāo)準(zhǔn)的,所以低版本的gcc源碼是沒有std::mem_fn的,建議選擇4.9.0或更新的版本去學(xué)習(xí),不同版本的gcc源碼差異應(yīng)該不小,但是原理和設(shè)計(jì)思想的一樣的,下面給出源碼下載地址
http://ftp.gnu.org/gnu/gcc

2、通過一個簡單的例子來了解std::mem_fn的作用

算法是C++標(biāo)準(zhǔn)庫中非常重要的組成部分,C++通過算法+容器的方式將數(shù)據(jù)結(jié)構(gòu)和算法進(jìn)行了分離,這樣可以使用戶編寫代碼的時(shí)候獲得最大限度的靈活性。假設(shè)我們有如下類:

class Age
{
public:
    Age(int v)
        :m_age(v)
    {
    }

    bool compare(const Age& t) const
    {
        return m_age < t.m_age;
    }

    int m_age;
};

我們可以非常方便地使用vector來保存Age對象,如下:

std::vector<Age> ages{1, 7, 19, 27, 39, 16, 13, 18};

然后非常方便的利用排序算法進(jìn)行排序

std::sort(ages.begin(), ages.end(), compare);

代碼中的compare是額外定義的一個比較函數(shù),通過這個函數(shù)來選擇比較的對象并決定比較的結(jié)果

bool compare(const Age& t1, const Age& t2)
{
    return t1.compare(t2);
}

嚴(yán)格來講,算法中要求的并不是函數(shù),而是一個可調(diào)用對象。C++中的可調(diào)用對象包括函數(shù)、函數(shù)對象、Lambda表達(dá)式、參數(shù)綁定等等,它們都可以作為算法的傳入?yún)?shù),但是如果我們按如下來傳入?yún)?shù)的話,則會在編譯過程中出現(xiàn)錯誤

std::sort(ages.begin(), ages.end(), &Age::compare);


因?yàn)?amp;Age::compare是類成員函數(shù),并非一個可調(diào)用對象,如果我們要將它作為比較的參數(shù)傳遞進(jìn)去的話,就得用std::mem_fn修飾它,如下所示

std::sort(ages.begin(), ages.end(), std::mem_fn(&Age::compare));

從上面的例子可以看到,std::mem_fn的作用就是將類的成員函數(shù)轉(zhuǎn)換為一個可調(diào)用對象,那么問題來了,std::mem_fn是如何實(shí)現(xiàn)這種功能的呢?下面讓我們通過分析源碼,來揭開std::mem_fn的神秘面紗。

3、std::mem_fn源碼解析

3.1、std::mem_fn解析

std::mem_fn位于libstdc++-v3\include\std\functional中

template<typename _Tp, typename _Class>
inline _Mem_fn<_Tp _Class::*> mem_fn(_Tp _Class::* __pm) noexcept
{
 return _Mem_fn<_Tp _Class::*>(__pm);
}

從代碼中可知std::mem_fn是一個模板函數(shù),傳入?yún)?shù)為指向_Class類里面的某個成員函數(shù)的指針,其返回值為_Tp,而該模板函數(shù)返回的值為_Mem_fn<_Tp _Class::*>,接下來看一下_Mem_fn的實(shí)現(xiàn)

3.2、std::_Mem_fn解析

std::_Mem_fn位于libstdc++-v3\include\std\functional中

template<typename _Res, typename _Class, typename... _ArgTypes>
class _Mem_fn<_Res (_Class::*)(_ArgTypes...)> : public _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...>
{
    typedef _Res (_Class::*_Functor)(_ArgTypes...);

    template<typename _Tp, typename... _Args>
    _Res _M_call(_Tp&& __object, const volatile _Class *, _Args&&... __args) const
    {
        return (std::forward<_Tp>(__object).*__pmf)(std::forward<_Args>(__args)...);
    }

    template<typename _Tp, typename... _Args>
    _Res _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const
    {
        return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...);
    }

    template<typename... _Args>
    using _RequireValidArgs = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>;

    template<typename _Tp, typename... _Args>
    using _RequireValidArgs2 = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>, _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>;

    template<typename _Tp, typename... _Args>
    using _RequireValidArgs3 = _Require<is_base_of<_Class, _Tp>, _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>;

public:
    typedef _Res result_type;

    explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) {}

    template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>>
    _Res operator()(_Class& __object, _Args&&... __args) const
    {
        return (__object.*__pmf)(std::forward<_Args>(__args)...);
    }

    template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>>
    _Res operator()(_Class&& __object, _Args&&... __args) const
    {
        return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...);
    }

    template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>>
    _Res operator()(_Class* __object, _Args&&... __args) const
    {
        return (__object->*__pmf)(std::forward<_Args>(__args)...);
    }

    template<typename _Tp, typename... _Args, typename _Req = _RequireValidArgs2<_Tp, _Args...>>
    _Res operator()(_Tp&& __object, _Args&&... __args) const
    {
        return _M_call(std::forward<_Tp>(__object), &__object,
        std::forward<_Args>(__args)...);
    }

    template<typename _Tp, typename... _Args,
    typename _Req = _RequireValidArgs3<_Tp, _Args...>>
    _Res operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const
    {
        return operator()(__ref.get(), std::forward<_Args>(__args)...);
    }

private:
    _Functor __pmf;
};

從源代碼中可以看出以下幾點(diǎn)信息:

  • 該類繼承于_Maybe_unary_or_binary_function,由于_Maybe_unary_or_binary_function和本文分析的內(nèi)容沒有太大關(guān)聯(lián),大家可以自行百度查詢其用法,這里就不多作介紹了
  • 類中有一個成員__pmf,其類型是指向上一節(jié)傳入mem_fn的那個類成員函數(shù)的指針,由構(gòu)造函數(shù)初始化
  • 接下來重點(diǎn)看一下類中六個重載的()運(yùn)算符函數(shù),里面的操作大同小異,基本都是通過__pmf對應(yīng)的類的對象(多種形式)來調(diào)用__pmf成員函數(shù)的:
    • 第一個函數(shù)_Res operator()(_Class& __object, _Args&&… __args):可以看到,其比原始的類成員函數(shù)多要求了一個傳入?yún)?shù),也就是__object,類型是一個類對象的引用,從函數(shù)的實(shí)現(xiàn)中可以看到原理就是通過這個類對象來直接調(diào)用先前那個類成員函數(shù)的(沒有這個類對象就調(diào)用不成立了,因?yàn)轭惓蓡T函數(shù)是無法直接調(diào)用的,這也是std::mem_fn存在的意義)
    • 第二個函數(shù)_Res operator()(_Class&& __object, _Args&&… __args):可以看到該方法第一個傳入?yún)?shù)是一個右值引用對象,里面的實(shí)現(xiàn)就是通過std::move將對象進(jìn)行轉(zhuǎn)移而已,其它處理與前面是完全一樣的
    • 第三個函數(shù)_Res operator()(_Class* __object, _Args&&… __args):可以看到該方法傳入了一個對象指針,其它處理與前面是完全一樣的
    • 第五個函數(shù)_Res operator()(reference_wrapper<_Tp> __ref, _Args&&… __args):可以看到該方法傳入了一個被std::reference_wrapper包裝的引用,流程和前面的基本一致,比較簡單,這里就不多作分析了(關(guān)于std::reference_wrapper的問題大家可以看一下這篇文章《C++11的std::ref、std::cref源碼解析》,里面有通過源碼分析對std::reference_wrapper作出了詳細(xì)的介紹,這里就不重復(fù)說明了)
    • 第四個函數(shù)_Res operator()(_Tp&& __object, _Args&&… __args):這個就比較復(fù)雜了,這個函數(shù)是為了處理傳入?yún)?shù)是智能指針或者派生類對象的一個情況的。可以看到函數(shù)里調(diào)用了_M_call方法,第二個參數(shù)看似可有可無,其實(shí)是為了用于給_M_call區(qū)分傳入?yún)?shù)類型是一個智能指針還是一個派生類對象的
  • _M_call實(shí)現(xiàn)如下,可以看到,第一個重載的形式是處理派生類對象的,第二個重載的形式是處理智能指針的,代碼比較簡單,這里就不多作分析了,大家可以自行看一遍就明白了
template<typename _Tp, typename... _Args>
_Res _M_call(_Tp&& __object, const volatile _Class *, _Args&&... __args) const
{
    return (std::forward<_Tp>(__object).*__pmf)(std::forward<_Args>(__args)...);
}

template<typename _Tp, typename... _Args>
_Res _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const
{
    return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...);
}

3.3、在代碼中正確使用std::_Mem_fn

示例代碼如下,從上面的一大段分析可以知道,我們傳入的ages[2]就是之前一直分析的那個用于調(diào)用類成員函數(shù)的那個傳入對象,而ages[3]就是bool Age::compare(const Age& t)所需要的正常的傳入?yún)?shù)了,也就是上面的可變參數(shù)里面的值。至此std::mem_fn源碼也就分析完畢了

#include <functional>
#include <iostream>
#include <algorithm>
#include <vector>

class Age
{
public:
    Age(int v)
        :m_age(v)
    {
    }

    bool compare(const Age& t) const
    {
        return m_age < t.m_age;
    }

    int m_age;
};

bool compare(const Age& t1, const Age& t2)
{
    return t1.compare(t2);
}

int main(int argc, char* argv[])
{
    std::vector<Age> ages{1, 7, 19, 27, 39, 16, 13, 18};
    bool ret = std::mem_fn(&Age::compare)(ages[2], ages[3]);
    //std::sort(ages.begin(), ages.end(), std::mem_fn(&Age::compare));

    return 0;
}

4、總結(jié)

std::mem_fn在函數(shù)式編程中的作用是非常大的,我們可以使用std::mem_fn生成指向類成員函數(shù)的指針的包裝對象,該對象可以存儲,復(fù)制和調(diào)用指向類成員函數(shù)的指針。而我們實(shí)際使用的是std::mem_fn的返回值std::_Mem_fn這個類,而我們在調(diào)用std::_Mem_fn中重載的()方法時(shí),可以使用類對象、派生類對象、對象引用(包括std::reference_wrapper)、對象的右值引用、指向?qū)ο蟮闹羔槪òㄖ悄苤羔槪﹣碜鳛榈谝粋€參數(shù)傳遞進(jìn)去。

到此這篇關(guān)于淺談C++11的std::mem_fn源碼解析的文章就介紹到這了,更多相關(guān)C++11 std::mem_fn源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Qt中QStackedWidget控件的使用

    詳解Qt中QStackedWidget控件的使用

    這篇文章主要為大家詳細(xì)介紹了Qt中QStackedWidget控件的具體使用,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下
    2023-02-02
  • C++選擇排序算法實(shí)例

    C++選擇排序算法實(shí)例

    這篇文章主要介紹了C++選擇排序算法實(shí)例,本文先是介紹了什么是選擇排序,然后給出了實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-10-10
  • 基于內(nèi)核線程的創(chuàng)建、使用和退出以及延時(shí)宏的補(bǔ)充說明介紹

    基于內(nèi)核線程的創(chuàng)建、使用和退出以及延時(shí)宏的補(bǔ)充說明介紹

    本篇文章是對內(nèi)核線程的創(chuàng)建、使用和退出以及延時(shí)宏的補(bǔ)充說明介紹進(jìn)行了敘述。需要的朋友參考下
    2013-05-05
  • c語言實(shí)現(xiàn)學(xué)生管理系統(tǒng)詳解

    c語言實(shí)現(xiàn)學(xué)生管理系統(tǒng)詳解

    這篇文章主要為大家介紹了c語言實(shí)現(xiàn)學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助<BR>
    2021-12-12
  • C語言動態(tài)內(nèi)存管理深入探討

    C語言動態(tài)內(nèi)存管理深入探討

    動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動態(tài)內(nèi)存的管理
    2022-06-06
  • C++中實(shí)現(xiàn)WebSocket通信的兩種方法:libwebsockets庫、Boost.Beast?庫

    C++中實(shí)現(xiàn)WebSocket通信的兩種方法:libwebsockets庫、Boost.Beast?庫

    C++中WebSocket庫主要有以下幾個?:cpp-websocket?、asio_websocket?、websockets++?、?websocketpp?、?libwebsockets?、?uWebSockets?、Boost.Beast?、Simple-WebSocket-Server?,這篇文章使用libwebsockets庫、Boost.Beast?庫來實(shí)現(xiàn)c++中的WebSocket通信
    2025-01-01
  • Embarcadero?Dev-C++輸出中文亂碼問題圖文詳解

    Embarcadero?Dev-C++輸出中文亂碼問題圖文詳解

    Dev-C++(或者叫做 Dev-Cpp)是Windows環(huán)境下的一個輕量級C/C++ 集成開發(fā)環(huán)境(IDE),下面這篇文章主要給大家介紹了關(guān)于Embarcadero?Dev-C++輸出中文亂碼問題的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • C++?自增自減運(yùn)算符的實(shí)現(xiàn)示例

    C++?自增自減運(yùn)算符的實(shí)現(xiàn)示例

    本文主要介紹了C++?自增自減運(yùn)算符的實(shí)現(xiàn)示例,自增和自減運(yùn)算符在C++中主要用于循環(huán)語句中,使循環(huán)變量的值自動+1或者-1,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • 詳解如何將Spire.XLS for C++集成到C++程序中

    詳解如何將Spire.XLS for C++集成到C++程序中

    Spire.XLS for C++ 是一個 Excel 庫,供開發(fā)人員在任何類型的 C++ 應(yīng)用程序中操作 Excel 文檔(XLS、XLSX、XLSB 和 XLSM)。 本文演示了如何以兩種不同的方式將 Spire.XLS for C++ 集成到您的 C++ 應(yīng)用程序中
    2023-03-03
  • C++ Boost Utility超詳細(xì)講解

    C++ Boost Utility超詳細(xì)講解

    Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱
    2022-12-12

最新評論

吉安市| 平陆县| 台南市| 大名县| 宜章县| 图片| 潍坊市| 安岳县| 雷州市| 蒲城县| 牙克石市| 托克托县| 逊克县| 始兴县| 囊谦县| 都昌县| 海南省| 石家庄市| 东源县| 荔波县| 江陵县| 旌德县| 泸定县| 南岸区| 当阳市| 池州市| 武宣县| 易门县| 永胜县| 济宁市| 咸宁市| 体育| 广西| 盐山县| 达孜县| 永安市| 资源县| 梨树县| 常宁市| 垣曲县| 于都县|