程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺析C++尺度庫元組(tuple)源碼

淺析C++尺度庫元組(tuple)源碼

編輯:關於C++

淺析C++尺度庫元組(tuple)源碼。本站提示廣大學習愛好者:(淺析C++尺度庫元組(tuple)源碼)文章只能為提供參考,不一定能成為您想要的結果。以下是淺析C++尺度庫元組(tuple)源碼正文


1、甚麼是元組

元組不是甚麼新穎器械,在數學、python說話還有我們明天要說的C++都有元組。

簡略地說,元組就是一組器械,例如,在講代數拓撲的時刻,常常把拓撲空間X和個中一點x作為一個偶對(X, x),這其實就是個元組,點的坐標也能夠算作一個元組。C++中的元組(tuple)是這個模樣的:

std::tuple<int, std::string> tu{ 2,"12iop" };

一個tuple可以包括分歧類型的成員,例如下面的tu包括一個int和一個字符串。

2、用法

在考核源碼之前,我們必需先曉得它的用法。

要想應用tuple,要包括頭文件<tuple>:

#include <tuple>

tuple現實上是一個有可變參數的類模板,應用的時刻,傳入若干個參數將其特化。

struct Point
{
 int x;
 int y;
};
 
void main()
{
 std::tuple<int, std::string> t1{ 1,"qwer" }; // 一個由int和字符串構成的tuple
 constexpr std::tuple<int, void*> t2{ 1,nullptr }; // 一個由int和void*構成的tuple
 std::tuple<int, Point> t3{ 1,{20,89} }; // 一個由int和Point構造體構成的tuple
 std::tuple<int, char, std::string> t4{ 1,'t',"qwer" }; // 一個由int、char、字符串構成的tuple
}

下面的代碼中,我用constexpr潤飾了t2,這是完整准確的,std::tuple的結構函數是constexpr的。

獲得tuple中的值,用std::get。這不是函數,而是函數模板,我們須要傳入size_t類型的變量將其特化,或許傳入一個類型,告知它我們須要掏出元組中的哪一個類型的成員。

struct Point
{
 int x;
 int y;
};
 
void main()
{
 std::tuple<int, std::string> t1{ 1,"qwer" };
 constexpr std::tuple<int, void*> t2{ 10,nullptr };
 std::tuple<int, Point> t3{ 1,{20,89} };
 std::tuple<int, char, std::string> t4{ 1,'t',"qwer" };
 
 std::cout << std::get<0>(t1) << std::endl; // 1
 
 constexpr int n2 = std::get<0>(t2);
 std::cout << n2 << std::endl; // 10
 
 auto s = std::get<char>(t4);
 std::cout << s << std::endl; // t
}

std::get也是constexpr的,所以n2也是一個編譯時的常量。

我們經由過程get<char>的方法獲得了s,它是char類型的變量。std::get<T>可以從tuple中獲得到第一個類型為T的成員。

tuple也能夠用【==】和【!=】比擬能否相等:

std::tuple<int, std::string> t5{ 1,"qwer" };
 
if (t1 == t5)
{
 std::cout << "==" << std::endl;
}

引見tuple的用法不是本文的重要內容,故到此為止。有興致的同窗可以自行查閱材料。

接上去,是時刻考核一看源碼了。

3、源碼剖析

tuple是個可變參數的類模板:

template<typename... _Types>
class tuple;

這是對類模板的聲明。

接上去,完成參數個數為零的空tuple。

3.1 tuple<>

struct allocator_arg_t
{};
 
template<>
class tuple<>
{
public:
 typedef tuple<> _Myt;
 
 constexpr tuple() noexcept
 {}
 
 template<typename _Alloc>
 tuple(allocator_arg_t, const _Alloc&) noexcept
 {}
 
 constexpr tuple(const tuple&) noexcept
 {}
 
 template<class _Alloc>
 tuple(allocator_arg_t, const _Alloc&, const _Myt&) noexcept
 {}
 
 void swap(_Myt&) noexcept
 {}
 
 constexpr bool _Equals(const _Myt&) const noexcept
 {
 return true;
 }
 
 constexpr bool _Less(const _Myt&) const noexcept
 {
 return false;
 }
};

allocator_arg_t是個空的構造體,臨時不論它。_Myt就是tuple<>本身,如許寫起來便利一些。

tuple<>界說了空的結構函數和拷貝結構函數(空tuple沒甚麼可做的)。

成員函數swap用於與另外一個tuple<>交流內容,由於沒甚麼可交流的,函數體固然是空的。

_Equals用來斷定兩個tuple<>能否相等,它前往true,這是明顯的(一切的tuple<>都是一個模樣)。

_Less從函數名看,是為了比擬年夜小,但假如碰到沒有重載<的類型呢?臨時不論它。

有了空tuple的界說,便可以界說非空的tuple。

3.2 非空的tuple

template<class _This,
class... _Rest>
class tuple<_This, _Rest...>
 : private tuple<_Rest...>
{
 // 內容
}

n(>0)個元素的tuple公有繼續了n-1個元素的tuple。明顯這是一種遞歸界說,終究會遞歸到tuple<>,而tuple<>是曾經界說好了得。

例如,tuple<int, char, short>公有繼續了tuple<char, short>,而tuple<char, short>又公有繼續了tuple<short>,tuple<short>公有繼續了tuple<>。因為公有繼續可以完成“has-a”功效,所以,如許的方法可以將分歧類型的對象組合在一路。以下圖:

那末,tuple是若何存儲個中的元素呢?

template<class _This,
class... _Rest>
class tuple<_This, _Rest...>
 : private tuple<_Rest...>
{ // recursive tuple definition
public:
 typedef _This _This_type;
 typedef tuple<_This, _Rest...> _Myt;
 typedef tuple<_Rest...> _Mybase;
 static const size_t _Mysize = 1 + sizeof...(_Rest);
 
 _Tuple_val<_This> _Myfirst; // 存儲的元素
}

本來,它有個成員叫_Myfirst,它就是用來存儲_This類型的變量的。你會看到_Myfirst的類型不是_This而是_Tuple_val<_This>,其實,_Tuple_val又是一個類模板,它的代碼這裡就不睜開了,簡而言之,它的感化是存儲一個tuple中的變量。_Myfirst._Val才是真實的元素。

這個tuple只存儲一個元素,類型為_Rest...的其他元素存在基類_MyBase即tuple<_Rest...>中。我們依然以tuple<int, char, short>為例,tuple<int, char, short>存儲了一個int,有基類tuple<char, short>;而tuple<char, short>存儲了一個char,有基類tuple<short>;tuple<short>存儲了一個short,有基類tuple<>;tuple沒有基類也不存儲任何元素。

3.3 結構函數

tuple的結構函數沒甚麼可說的,就是初始化_Myfirst和_MyBase,固然,_MyBase也要停止麼一個進程,直到tuple<>。

 constexpr tuple(): _Mybase(), _Myfirst()
 {}
 
 constexpr explicit tuple(const _This& _This_arg,
 const _Rest&... _Rest_arg)
 : _Mybase(_Rest_arg...),
 _Myfirst(_This_arg)
 {}
 
 tuple(const _Myt&) = default;
 tuple(_Myt&&) = default;

它還供給了默許拷貝結構函數和挪動結構函數(挪動語義是C++11中新增的特征,請自行查閱材料)。其實,它還有許多結構函數,寫起來挺熱烈,不過就是用分歧的方法為它賦初值,故省略。

3.4 部門成員函數

tuple重載了賦值符號(=),如許,tuple之間是可以賦值的

 template<class... _Other>
 _Myt& operator=(const tuple<_Other...>& _Right)
 { // assign by copying same size tuple
 _Myfirst._Val = _Right._Myfirst._Val;
 _Get_rest() = _Right._Get_rest();
 return (*this);
 }

賦值符號前往右邊的援用,這類行動和C++的內置類型是分歧的。_Get_rest是tuple的成員函數,感化是把除_Myfirst以外的那些元素拿出來。

接上去是成員函數_Equals,

template<class... _Other>
constexpr bool _Equals(const tuple<_Other...>& _Right) const
{
 static_assert(_Mysize == sizeof...(_Other), "comparing tuple to object with different size");
 return (_Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest()));
}

個中停止了靜態斷言,假如兩個tuple的元素個數不雷同,會激發一個編譯時的毛病。假如對應的類型不克不及用==停止比擬,在模板特化時也會激發編譯期的毛病,例如,tuple<std::string, int>不克不及和tuple<int, char>比擬,由於std::string和int是不克不及用==停止比擬的。

後面提到的_Get_rest在這裡:

_Mybase& _Get_rest() noexcept
{
 return (*this);
}
 
constexpr const _Mybase& _Get_rest() const noexcept
{
 return (*this);
}

它前往對基類的援用。*this的類型固然是_Myt,但依據C++語法(可以把派生類的援用賦給對基類的援用),所以如許做是沒成績的。

以上就是C++尺度庫元組(tuple)源碼淺析的全體內容,願望對年夜家的進修有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved