中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

c++的traits方法實例分析

發布時間:2022-03-28 10:43:23 來源:億速云 閱讀:318 作者:iii 欄目:大數據

今天小編給大家分享一下c++的traits方法實例分析的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

說明一下,我用的是gcc7.1.0編譯器,標準庫源代碼也是這個版本的。

還是先看一下思維導圖,如下:

c++的traits方法實例分析

1. 指針萃取器pointer_traits說明

首先說明一下哈,官方并沒有指針萃取器這個名稱,其實pointer_traits是類模板,它是c++11以后引入的,可以通過傳入的重綁定模板類型得到相應的指針類型,比較官方的描述是:pointer_traits 類模板提供標準化方法,用于訪問類指針類型的某些屬性。

那么為什么要把這個pointer_traits拿出來單獨說明一下呢,因為類似之前的內存分配器一樣,它是stl中某些容器的使用前提,在講容器的時候,繞不開它,所以先把它搞清楚了有助于后續的學習和理解。

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

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

類模板pointer_traits在標準庫中有兩個版本,一個特化版本,一個非特化版本,源代碼都在bits/ptr_traits.h頭文件中,當然實際使用的時候它是被包含在頭文件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參數里面類型存在則直接使用下面這個結構體,否則使用上面那個
      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>");
    };

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

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

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

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

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

  • pointer,這個其實就是模板參數_ptr的一個別名;

  • element_type,也是一個別名,如果_ptr::element_type這個類型存在,則它就是_ptr::element_type這個類型,如果_ptr::element_type這個類型不存在,但是_ptr是一個模板特化,則它就是_ptr,否則就是__undefined,其實就是無意義類型了;

  • difference_type,也是一個別名,如果_ptr::difference_type這個類型存在,則它就是_ptr::difference_type,否則就是ptrdiff_t類型;

  • template<typename _Up>using rebind,它是一個類型別名模板,由類pointer_traits的模板參數和rebind的模板參數一起決定最終到底是什么類型,若_ptr::rebind&lt;_Up&gt;這個類型存在則它就是_ptr::rebind&lt;_Up&gt;,否則根據類型模板__replace_first_arg的實現,若_ptr是模板特化_Template&lt;_Tp, _Types...&gt;,則它是_Template&lt;_Tp, _Types...&gt;,否則就沒有類型;

  • pointer_to,它是一個靜態成員函數,調用模板類型的pointer_to函數,所以具體什么作用取決于_ptr的實現,但根據字面意思應該是獲取element_type類型對象的地址。

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

2.2 特化pointer_traits

接下來看一下特化類模板pointer_traits的源代碼實現:

template<typename _Tp>
    struct pointer_traits<_Tp*>
    {
      typedef _Tp* pointer;   //為特化類型取個別名
      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); }
    };

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

源代碼分析完以后,貌似有點印象了,但是我們具體應該怎么使用呢?

3. 指針萃取器的簡單使用

我們先寫一段例子代碼,如下:

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

//將gcc編譯出來的類型翻譯為真實的類型
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;
}

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

double*

看上面的代碼,我們還是不知道pointer_traits到底有啥作用,并且看起來是把簡單的類型搞復雜了,但有一點,當我們不知道確切類型的時候,使用這個標準模板類獲取指針類型還是蠻方便的,這一點在標準庫的deque容器中就有使用。

而對于非特化的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;
}

說白了,從這里看pointer_traits的作用就是得到某些類型的屬性,這個在類型未知的時候就比較有用,比較典型的用法是在標準庫的allocator_traits類模板里面,我們之前說過,allocator_traits是內存萃取器,在這個萃取器里面,會通過pointer_traits獲取一些分配器的類型屬性。

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

所謂traits,字面意思是特性、特征,所以說白了,traits技法其實就是獲取未知類型的某些屬性,為什么說是未知,因為traits主要用于模板編程中,根據模板類型去獲取某些類型特性,如果是已知的類型,那就沒有必要使用traits技法了。

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

下面我們再看一看怎么使用非特化的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特性。

以上就是“c++的traits方法實例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海宁市| 嘉禾县| 郴州市| 涞水县| 奎屯市| 哈尔滨市| 勃利县| 建始县| 玉田县| 普洱| 忻州市| 瓦房店市| 凌海市| 吉木萨尔县| 门头沟区| 洪雅县| 梁平县| 澳门| 栖霞市| 屯留县| 澎湖县| 通州区| 包头市| 尉氏县| 息烽县| 丰原市| 日照市| 屯门区| 巴彦县| 崇仁县| 台湾省| 哈密市| 祁阳县| 景泰县| 时尚| 民丰县| 青阳县| 泰顺县| 瓦房店市| 福建省| 且末县|