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

從c++標(biāo)準(zhǔn)庫(kù)指針萃取器談一下traits技法(推薦)

 更新時(shí)間:2021年07月14日 11:32:42   作者:cpp加油站  
本篇文章基于gcc中標(biāo)準(zhǔn)庫(kù)源碼剖析一下標(biāo)準(zhǔn)庫(kù)中的模板類pointer_traits,并且以此為例理解一下traits技法,對(duì)c++ traits技法源碼分析感興趣的朋友跟隨小編一起看看吧

本篇文章基于gcc中標(biāo)準(zhǔn)庫(kù)源碼剖析一下標(biāo)準(zhǔn)庫(kù)中的模板類pointer_traits,并且以此為例理解一下traits技法。

說(shuō)明一下,我用的是gcc7.1.0編譯器,標(biāo)準(zhǔn)庫(kù)源代碼也是這個(gè)版本的。

還是先看一下思維導(dǎo)圖,如下:

1. 指針萃取器pointer_traits說(shuō)明

首先說(shuō)明一下哈,官方并沒(méi)有指針萃取器這個(gè)名稱,其實(shí)pointer_traits是類模板,它是c++11以后引入的,可以通過(guò)傳入的重綁定模板類型得到相應(yīng)的指針類型,比較官方的描述是:pointer_traits 類模板提供標(biāo)準(zhǔn)化方法,用于訪問(wèn)類指針類型的某些屬性。

那么為什么要把這個(gè)pointer_traits拿出來(lái)單獨(dú)說(shuō)明一下呢,因?yàn)轭愃浦暗膬?nèi)存分配器一樣,它是stl中某些容器的使用前提,在講容器的時(shí)候,繞不開(kāi)它,所以先把它搞清楚了有助于后續(xù)的學(xué)習(xí)和理解。

為什么要叫指針萃取器呢,我理解它類似于內(nèi)存萃取器allocator_traits,都是根據(jù)模板參數(shù)去得到某種類型,并且traits也有萃取的意思,所以我這里就叫指針萃取器了。

2. 指針萃取器源代碼分析

類模板pointer_traits在標(biāo)準(zhǔn)庫(kù)中有兩個(gè)版本,一個(gè)特化版本,一個(gè)非特化版本,源代碼都在bits/ptr_traits.h頭文件中,當(dāng)然實(shí)際使用的時(shí)候它是被包含在頭文件memory中的。

2.1 非特化pointer_traits

我們先分析一下非特化版本的源代碼,如下:

//pointer_traits類模板
template<typename _Ptr>
    struct pointer_traits
    {
    private:
	template<typename _Tp>
	using __element_type = typename _Tp::element_type;

      template<typename _Tp>
	using __difference_type = typename _Tp::difference_type;

      template<typename _Tp, typename _Up, typename = void>
	struct __rebind : __replace_first_arg<_Tp, _Up> { };

      //如果__void_t參數(shù)里面類型存在則直接使用下面這個(gè)結(jié)構(gòu)體,否則使用上面那個(gè)
      template<typename _Tp, typename _Up>
	struct __rebind<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up>>>
	{ using type = typename _Tp::template rebind<_Up>; };

    public:
      using pointer = _Ptr;
        
      using element_type
	= __detected_or_t<__get_first_arg_t<_Ptr>, __element_type, _Ptr>;

      using difference_type
	= __detected_or_t<ptrdiff_t, __difference_type, _Ptr>;

      template<typename _Up>
        using rebind = typename __rebind<_Ptr, _Up>::type;

      static _Ptr
      pointer_to(__make_not_void<element_type>& __e)
      { return _Ptr::pointer_to(__e); }

      static_assert(!is_same<element_type, __undefined>::value,
	  "pointer type defines element_type or is like SomePointer<T, Args>");
    };

對(duì)于這段代碼,其實(shí)初看起來(lái)是有點(diǎn)懵的,但是萬(wàn)變不離其宗,一個(gè)類被定義出來(lái),最后是給別人使用的,所以對(duì)于類類型而言,我們只要搞懂它的公共成員都有些什么作用,那大概也就知道這個(gè)類的作用了。

這里需要說(shuō)明一下__detected_or_t的作用,它也是一個(gè)類型模板,聲明如下:

template<typename _Default, template<typename...> class _Op,
	   typename... _Args>
    using __detected_or_t
      = typename __detected_or<_Default, _Op, _Args...>::type;

作用是如果_Op&lt;_Args...&gt;是一個(gè)有效的類型,那這個(gè)類型就是_Op&lt;_Args...&gt;,否則就是_Default

那么對(duì)于類模板pointer_traits,它的公共成員作用如下:

  • pointer,這個(gè)其實(shí)就是模板參數(shù)_ptr的一個(gè)別名;
  • element_type,也是一個(gè)別名,如果_ptr::element_type這個(gè)類型存在,則它就是_ptr::element_type這個(gè)類型,如果_ptr::element_type這個(gè)類型不存在,但是_ptr是一個(gè)模板特化,則它就是_ptr,否則就是__undefined,其實(shí)就是無(wú)意義類型了;
  • difference_type,也是一個(gè)別名,如果_ptr::difference_type這個(gè)類型存在,則它就是_ptr::difference_type,否則就是ptrdiff_t類型;
  • template<typename _Up>using rebind,它是一個(gè)類型別名模板,由類pointer_traits的模板參數(shù)和rebind的模板參數(shù)一起決定最終到底是什么類型,若_ptr::rebind&lt;_Up&gt;這個(gè)類型存在則它就是_ptr::rebind&lt;_Up&gt;,否則根據(jù)類型模板__replace_first_arg的實(shí)現(xiàn),若_ptr是模板特化_Template&lt;_Tp, _Types...&gt;,則它是_Template&lt;_Tp, _Types...&gt;,否則就沒(méi)有類型;
  • pointer_to,它是一個(gè)靜態(tài)成員函數(shù),調(diào)用模板類型的pointer_to函數(shù),所以具體什么作用取決于_ptr的實(shí)現(xiàn),但根據(jù)字面意思應(yīng)該是獲取element_type類型對(duì)象的地址。

所以總的來(lái)看,說(shuō)白了類模板pointer_traits其實(shí)就是用于獲取模板參數(shù)_ptr的某些類型屬性,那從這里反推一下,也能知道這個(gè)模板參數(shù)類型需要具有一些什么屬性。

2.2 特化pointer_traits

接下來(lái)看一下特化類模板pointer_traits的源代碼實(shí)現(xiàn):

template<typename _Tp>
    struct pointer_traits<_Tp*>
    {
      typedef _Tp* pointer;   //為特化類型取個(gè)別名
      typedef _Tp  element_type;   //為模板類型取別名
      typedef ptrdiff_t difference_type; 

      template<typename _Up>
        using rebind = _Up*;

      static pointer
      pointer_to(__make_not_void<element_type>& __r) noexcept
      { return std::addressof(__r); }
    };

對(duì)于特化類型,它的公共成員與非特化其實(shí)是一致的,只是它是為_Tp*類型提供的特化,對(duì)于其他公共成員,這里比較簡(jiǎn)單,就不再多說(shuō)了,重點(diǎn)再看一下template&lt;typename _Up&gt; using rebind這個(gè)類型別名模板,它直接獲取一個(gè)_Up*類型的指針,結(jié)合整體來(lái)看,它的作用就是:重綁定類型成員模板別名,使得可以由指向 _Tp 的指針類型,獲取指向 _Up 的指針類型。

源代碼分析完以后,貌似有點(diǎn)印象了,但是我們具體應(yīng)該怎么使用呢?

3. 指針萃取器的簡(jiǎn)單使用

我們先寫(xiě)一段例子代碼,如下:

#include <memory>
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>

//將gcc編譯出來(lái)的類型翻譯為真實(shí)的類型
const char* GetRealType(const char* p_szSingleType)
{
    const char* szRealType = abi::__cxa_demangle(p_szSingleType, nullptr, nullptr, nullptr);
    return szRealType;
}

int main()
{
	using ptr = typename std::pointer_traits<int*>::template rebind<double>;
	ptr p1;
	const std::type_info &info = typeid(p1);
	std::cout << GetRealType(info.name()) << std::endl;
	return 0;
}

上面這個(gè)例子很顯然用到了特化的pointer_traits,并且用的rebind屬性,由指向int的指針類型獲得了指向double的指針類型,代碼輸出如下:

double*

看上面的代碼,我們還是不知道pointer_traits到底有啥作用,并且看起來(lái)是把簡(jiǎn)單的類型搞復(fù)雜了,但有一點(diǎn),當(dāng)我們不知道確切類型的時(shí)候,使用這個(gè)標(biāo)準(zhǔn)模板類獲取指針類型還是蠻方便的,這一點(diǎn)在標(biāo)準(zhǔn)庫(kù)的deque容器中就有使用。

而對(duì)于非特化的pointer_traits,看一下下面這段代碼:

#include <memory>
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#include <string>

struct test_traits
{
	using element_type = int;
	using difference_type = double;
};

struct test_traits2
{
	using element_type = std::string;
	using difference_type = size_t;
};

const char* GetRealType(const char* p_szSingleType)
{
    const char* szRealType = abi::__cxa_demangle(p_szSingleType, nullptr, nullptr, nullptr);
    return szRealType;
}

int main()
{
	using type1 = typename std::pointer_traits<test_traits>::element_type;
	using type2 = typename std::pointer_traits<test_traits2>::difference_type;
	const std::type_info &info = typeid(type1);
	std::cout << GetRealType(info.name()) << std::endl;
	const std::type_info &info2 = typeid(type2);
	std::cout << GetRealType(info2.name()) << std::endl;
	return 0;
}

說(shuō)白了,從這里看pointer_traits的作用就是得到某些類型的屬性,這個(gè)在類型未知的時(shí)候就比較有用,比較典型的用法是在標(biāo)準(zhǔn)庫(kù)的allocator_traits類模板里面,我們之前說(shuō)過(guò),allocator_traits是內(nèi)存萃取器,在這個(gè)萃取器里面,會(huì)通過(guò)pointer_traits獲取一些分配器的類型屬性。

4. 從指針萃取器角度談traits技法

所謂traits,字面意思是特性、特征,所以說(shuō)白了,traits技法其實(shí)就是獲取未知類型的某些屬性,為什么說(shuō)是未知,因?yàn)閠raits主要用于模板編程中,根據(jù)模板類型去獲取某些類型特性,如果是已知的類型,那就沒(méi)有必要使用traits技法了。

比如本篇文章所講的pointer_traits,它就是使用traits技法的典型案例,按照字面意思我們可以理解為指針的特性,所以非特化的pointer_traits它就是用于獲取某些類指針的類型特性,而一般特化的pointer_traits其實(shí)是用于原生指針類型,比如int*這樣的。

下面我們?cè)倏匆豢丛趺词褂梅翘鼗?code>pointer_traits獲取類指針的特性,如下:

#include <memory>
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>

const char* GetRealType(const char* p_szSingleType)
{
    const char* szRealType = abi::__cxa_demangle(p_szSingleType, nullptr, nullptr, nullptr);
    return szRealType;
}

int main()
{
	using type = typename std::pointer_traits<std::shared_ptr<int>>::element_type;
	const std::type_info &info = typeid(type);
	std::cout << GetRealType(info.name()) << std::endl;
	return 0;
}

代碼輸出:int,它獲取了智能指針的element_type特性。

到此這篇關(guān)于從c++標(biāo)準(zhǔn)庫(kù)指針萃取器談一下traits技法的文章就介紹到這了,更多相關(guān)c++ traits技法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c++ 前自增/后自增操作符效率分析

    c++ 前自增/后自增操作符效率分析

    這篇文章主要介紹了c++ 前自增/后自增操作符效率分析,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2021-01-01
  • C/C++實(shí)現(xiàn)string和int相互轉(zhuǎn)換的常用方法總結(jié)

    C/C++實(shí)現(xiàn)string和int相互轉(zhuǎn)換的常用方法總結(jié)

    在C++編程中,經(jīng)常需要在字符串(string)和整型(int)之間進(jìn)行轉(zhuǎn)換,本文將詳細(xì)介紹幾種在C和C++中實(shí)現(xiàn)這兩種類型轉(zhuǎn)換的常用方法,有需要的可以參考下
    2024-01-01
  • 淺析C/C++中sort函數(shù)的用法

    淺析C/C++中sort函數(shù)的用法

    做項(xiàng)目的時(shí)候,排序是一種經(jīng)常要用到的操作。如果每次都自己寫(xiě)個(gè)冒泡之類的O(n^2)排序,不但程序容易超時(shí),而且浪費(fèi)寶貴的時(shí)間,還很有可能寫(xiě)錯(cuò)。STL里面有個(gè)sort函數(shù),可以直接對(duì)數(shù)組排序,復(fù)雜度為n*log2(n)。
    2014-09-09
  • C++ 中二分查找遞歸非遞歸實(shí)現(xiàn)并分析

    C++ 中二分查找遞歸非遞歸實(shí)現(xiàn)并分析

    這篇文章主要介紹了C++ 中二分查找遞歸非遞歸實(shí)現(xiàn)并分析的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C++ 中循環(huán)鏈表和約瑟夫環(huán)

    C++ 中循環(huán)鏈表和約瑟夫環(huán)

    這篇文章主要介紹了C++ 中循環(huán)鏈表和約瑟夫環(huán)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C++使用OpenCV實(shí)現(xiàn)證件照藍(lán)底換成白底功能(或其他顏色如紅色)詳解

    C++使用OpenCV實(shí)現(xiàn)證件照藍(lán)底換成白底功能(或其他顏色如紅色)詳解

    這篇文章主要介紹了C++使用OpenCV實(shí)現(xiàn)證件照藍(lán)底換成白底功能(或其他顏色如紅色),結(jié)合實(shí)例形式詳細(xì)分析了OpenCV顏色轉(zhuǎn)換相關(guān)操作原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-12-12
  • QT5實(shí)現(xiàn)電子時(shí)鐘

    QT5實(shí)現(xiàn)電子時(shí)鐘

    這篇文章主要為大家詳細(xì)介紹了QT5實(shí)現(xiàn)電子時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C++抽象基類講解

    C++抽象基類講解

    這篇文章主要介紹了C++抽象基類講解,象基類abstract base class簡(jiǎn)稱ABC,C++實(shí)現(xiàn)繼承的時(shí)候,需要保證派生類和基類之間是一種is-a的關(guān)系。在大多數(shù)時(shí)刻,這樣的關(guān)系是沒(méi)有問(wèn)題的,然而在一些特殊的情況可能會(huì)遇到問(wèn)題,下面來(lái)看看文章的具體介紹吧
    2022-01-01
  • C++ sort排序之降序、升序使用總結(jié)

    C++ sort排序之降序、升序使用總結(jié)

    這篇文章主要介紹了C++ sort 排序(降序、升序)使用總結(jié),需要的朋友可以參考下
    2020-11-11
  • C++如何實(shí)現(xiàn)sha256算法

    C++如何實(shí)現(xiàn)sha256算法

    SHA-256算法由于其強(qiáng)大的安全性,已成為國(guó)際標(biāo)準(zhǔn)和許多安全協(xié)議的推薦算法,在密碼存儲(chǔ)、數(shù)字簽名、區(qū)塊鏈技術(shù)、SSL/TLS協(xié)議、數(shù)據(jù)完整性驗(yàn)證、系統(tǒng)安全審計(jì)等眾多應(yīng)用領(lǐng)域,SHA-256算法都至關(guān)重要,這篇文章主要介紹了C++如何實(shí)現(xiàn)sha256算法,需要的朋友可以參考下
    2024-07-07

最新評(píng)論

姜堰市| 辽中县| 庆阳市| 宁武县| 安泽县| 山东省| 竹山县| 朝阳市| 阿坝| 舞阳县| 虞城县| 于田县| 南漳县| 扶风县| 纳雍县| 阜宁县| 曲麻莱县| 罗江县| 开封县| 凤翔县| 连南| 望奎县| 察隅县| 长春市| 贵溪市| 观塘区| 福清市| 江油市| 郑州市| 开封县| 阳新县| 沙坪坝区| 崇左市| 广安市| 西林县| 雷波县| 凌海市| 钦州市| 台北市| 浪卡子县| 昭通市|