真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

C++11中的std::mem_fn怎么用-創(chuàng)新互聯(lián)

這篇“C++11中的std::mem_fn怎么用”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“C++11中的std::mem_fn怎么用”文章吧。

創(chuàng)新互聯(lián)專(zhuān)注于峽江網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供峽江營(yíng)銷(xiāo)型網(wǎng)站建設(shè),峽江網(wǎng)站制作、峽江網(wǎng)頁(yè)設(shè)計(jì)、峽江網(wǎng)站官網(wǎng)定制、重慶小程序開(kāi)發(fā)公司服務(wù),打造峽江網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供峽江網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。

1、源碼準(zhǔn)備

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

2、通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)了解std::mem_fn的作用

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

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來(lái)保存Age對(duì)象,如下:

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

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

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

代碼中的compare是額外定義的一個(gè)比較函數(shù),通過(guò)這個(gè)函數(shù)來(lái)選擇比較的對(duì)象并決定比較的結(jié)果

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

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

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

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

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

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

3、std::mem_fn源碼解析

3.1、std::mem_fn解析

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

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

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

3.2、std::_Mem_fn解析

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

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

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

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

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

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

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

public:
    typedef _Res result_type;

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

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

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

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

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

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

private:
    _Functor __pmf;
};

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

  • 該類(lèi)繼承于_Maybe_unary_or_binary_function,由于_Maybe_unary_or_binary_function和本文分析的內(nèi)容沒(méi)有太大關(guān)聯(lián),大家可以自行百度查詢(xún)其用法,這里就不多作介紹了

  • 類(lèi)中有一個(gè)成員__pmf,其類(lèi)型是指向上一節(jié)傳入mem_fn的那個(gè)類(lèi)成員函數(shù)的指針,由構(gòu)造函數(shù)初始化

  • 接下來(lái)重點(diǎn)看一下類(lèi)中六個(gè)重載的()運(yùn)算符函數(shù),里面的操作大同小異,基本都是通過(guò)__pmf對(duì)應(yīng)的類(lèi)的對(duì)象(多種形式)來(lái)調(diào)用__pmf成員函數(shù)的:

    • 第一個(gè)函數(shù)_Res operator()(_Class& __object, _Args&&… __args):可以看到,其比原始的類(lèi)成員函數(shù)多要求了一個(gè)傳入?yún)?shù),也就是__object,類(lèi)型是一個(gè)類(lèi)對(duì)象的引用,從函數(shù)的實(shí)現(xiàn)中可以看到原理就是通過(guò)這個(gè)類(lèi)對(duì)象來(lái)直接調(diào)用先前那個(gè)類(lèi)成員函數(shù)的(沒(méi)有這個(gè)類(lèi)對(duì)象就調(diào)用不成立了,因?yàn)轭?lèi)成員函數(shù)是無(wú)法直接調(diào)用的,這也是std::mem_fn存在的意義)

    • 第二個(gè)函數(shù)_Res operator()(_Class&& __object, _Args&&… __args):可以看到該方法第一個(gè)傳入?yún)?shù)是一個(gè)右值引用對(duì)象,里面的實(shí)現(xiàn)就是通過(guò)std::move將對(duì)象進(jìn)行轉(zhuǎn)移而已,其它處理與前面是完全一樣的

    • 第三個(gè)函數(shù)_Res operator()(_Class* __object, _Args&&… __args):可以看到該方法傳入了一個(gè)對(duì)象指針,其它處理與前面是完全一樣的

    • 第五個(gè)函數(shù)_Res operator()(reference_wrapper<_Tp> __ref, _Args&&… __args):可以看到該方法傳入了一個(gè)被std::reference_wrapper包裝的引用,流程和前面的基本一致,比較簡(jiǎn)單,這里就不多作分析了(關(guān)于std::reference_wrapper的問(wèn)題大家可以看一下這篇文章《C++11的std::ref、std::cref源碼解析》,里面有通過(guò)源碼分析對(duì)std::reference_wrapper作出了詳細(xì)的介紹,這里就不重復(fù)說(shuō)明了)

    • 第四個(gè)函數(shù)_Res operator()(_Tp&& __object, _Args&&… __args):這個(gè)就比較復(fù)雜了,這個(gè)函數(shù)是為了處理傳入?yún)?shù)是智能指針或者派生類(lèi)對(duì)象的一個(gè)情況的。可以看到函數(shù)里調(diào)用了_M_call方法,第二個(gè)參數(shù)看似可有可無(wú),其實(shí)是為了用于給_M_call區(qū)分傳入?yún)?shù)類(lèi)型是一個(gè)智能指針還是一個(gè)派生類(lèi)對(duì)象的

  • _M_call實(shí)現(xiàn)如下,可以看到,第一個(gè)重載的形式是處理派生類(lèi)對(duì)象的,第二個(gè)重載的形式是處理智能指針的,代碼比較簡(jiǎn)單,這里就不多作分析了,大家可以自行看一遍就明白了

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

template
_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]就是之前一直分析的那個(gè)用于調(diào)用類(lèi)成員函數(shù)的那個(gè)傳入對(duì)象,而ages[3]就是bool Age::compare(const Age& t)所需要的正常的傳入?yún)?shù)了,也就是上面的可變參數(shù)里面的值。至此std::mem_fn源碼也就分析完畢了

#include 
#include 
#include 
#include 

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 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;
}

以上就是關(guān)于“C++11中的std::mem_fn怎么用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


分享題目:C++11中的std::mem_fn怎么用-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://weahome.cn/article/dsopdc.html

其他資訊

在線咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部