<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
(1)當編譯器看到{t1,t2…tn}時便會生成一個initializer_list<T>物件(其中的T為元素的型別),它關聯到一個array<T,n>。
(2)對於聚合型別,編譯器會將array<T,n>內的元素逐一分解並賦值給被初始化的物件。這相當於為該物件每個欄位分別賦值。
(3)對於非聚合型別。如果該類存在一個接受initializer_list<T>型別的建構函式,則初始化時會將initializer_list<T>物件作為一個整體傳給建構函式。如果不存在這樣的建構函式,則array內的元素會被編譯器分解並傳給相應的能接受這些引數的建構函式(比如列表中有2個元素的,就傳給帶2個引數的建構函式。有3個元素的,就傳給帶3個引數的建構函式,依此類推……)。
【範例分析】initializer_list<T>初體驗
#include <iostream> #include <vector> #include <map> #include <complex> using namespace std; //編譯選項:g++ -std=c++11 test1.cpp -fno-elide-constructors class Foo { public: Foo(int) { cout << "Foo(int)"<< endl; } Foo(int, int) cout << "Foo(int, int)"<< endl; Foo(const Foo& f) cout << "Foo(const Foo& f)"<< endl; }; int main() Foo f1(123); Foo f2 = 123; //先將呼叫Foo(int)將123轉為Foo物件,再呼叫拷貝建構函式(後面這步可能被優化) Foo f3 = {123}; //生成initializer_list<int>,然後分解元素後,由於列表中只有1個元素,所以將其傳給Foo(int) Foo f4 = {123, 321}; //生成initializer_list<int>,然後分解元素後,由於列表中有兩個元素,所以將其傳給Foo(int, int) //編譯器會為以下花括號形成一個initializer_list<string>,背後有個array<string,6> //呼叫vector<string>的建構函式時,編譯器會找到一個接受initializer_list<string> //的過載的建構函式。所有的容器均有這樣的建構函式。在這個建構函式裡會利用 //initializer_list<string>來初始化。 vector<string> city{"Berlin", "New York", "London", "Cairo","Tokyo", "Cologne"}; //編譯器會為以下花括號形成一個initializer_list<double>,背後有個array<double,2>。 //呼叫complex<double>的建構函式時,array內的2個元素被分解並傳給 //Comlex<double>(double,double)這個帶有兩個引數的建構函式。因為comlex<double>並無 //任何接受initializer_list的建構函式。 complex<double> c{4.0, 3.0}; //等價於c(4.0, 3.0) return 0; }
//initializer_list<T>原始碼分析
#include <iostream> template <class T> class initializer_list { public: typedef T value_type; typedef const T& reference; //注意說明該物件永遠為const,不能被外部修改! typedef const T& const_reference; typedef size_t size_type; typedef const T* iterator; //永遠為const型別 typedef const T* const_iterator; private: iterator _M_array; //用於存放用{}初始化列表中的元素 size_type _M_len; //元素的個數 //編譯器可以呼叫private的建構函式!!! //建構函式,在呼叫之前,編譯會先在外部準備好一個array,同時把array的地址傳入模板 //並儲存在_M_array中 constexpr initializer_list(const_iterator __a, size_type __l) :_M_array(__a),_M_len(__l){}; //注意建構函式被放到private中! constexpr initializer_list() : _M_array(0), _M_len(0){} // empty list,無參建構函式 //size()函數,用於獲取元素的個數 constexpr size_type size() const noexcept {return _M_len;} //獲取第一個元素 constexpr const_iterator begin() const noexcept {return _M_array;} //最後一個元素的下一個位置 constexpr const_iterator end() const noexcept { return begin() + _M_len; } };
(1)initializer_list是一個輕量級的容器型別,內部定義了iterator等容器必需的概念,本質上是一個迭代器!
(2)對於std:: initializer_list<T>而言,它可以接收任意長度的初始化列表,但要求元素必須是同種型別(T或可轉換為T)。
(3)它有3個成員函數:size()、begin()和end()。
(4)擁有一個無參建構函式,可以被直接範例化,此時將得到一個空的列表。之後可以進行賦值操作,如initializer_list<int> list; list={1,2,3,4,5};
(5)initializer_list<T>在進行復制或賦值時,它內部將儲存著列表的地址儲存在_M_array中,它進行的是淺拷貝,並不真正複製每個元素,因此效率很高。
【程式設計實驗】列印初始化列表的每個元素
#include <iostream> //列印初始化列表的每個元素 void print(std::initializer_list<int> vals) { //遍歷列表中的每個元素 for(auto p = vals.begin(); p!=vals.end(); ++p){ std::cout << *p << " "; } std::cout << std::endl; } //std::initializer_list<T>的淺拷貝。以下的返回值應改為std //以下的返回值應改為std::vector<int>型別,而不是std::initializer_list<int>型別。 std::initializer_list<int> func(void) int a = 1; int b = 2; return {a, b}; //編譯器看到{a, b}時,會做好一個array<int,2>物件(其生命 //期直至func結束),然後再產生一個initializer_list<int> //臨時物件,由於initializer_list<int>採用的是淺拷貝,當 //函數返回後array<int,2>會被釋放,所以無法獲取到列表中的元素! int main() print({1,2,3,4,5,6,7,8,9,10}); print(func()); return 0; /*測試結果: e:StudyC++117>g++ -std=c++11 test1.cpp e:StudyC++117>a.exe 1 2 3 4 5 6 7 8 9 10 */
(1)自定義類中過載一個可接受initializer_list<T>型別的建構函式
(2)在該建構函式中,遍歷列表元素並賦值給相應的欄位。
【程式設計實驗】自定義類的初始化列表
#include <iostream> #include <map> using namespace std; class Foo { public: Foo(int a, int b) { cout << "Foo(int a, int b)" << endl; } Foo(initializer_list<int> list) cout << "Foo(initializer_list<int> list) : "; for(auto i : list){ cout <<i<< " "; } cout << endl; }; class FooMap std::map<int, int> content; using pair_t = std::map<int, int>::value_type; FooMap(std::initializer_list<pair_t> list) for(auto it = list.begin(); it!=list.end(); ++it){ content.insert(*it); std::cout << "{" << (*it).first <<"," <<(*it).second <<"}" << " "; std::cout << std::endl; int main() Foo f1(77, 5); //Foo(int a, int b), a = 77, b = 5; //注意:由於定義了Foo(initializer_list<int> list)函數,以下3種方 //式的初始化都會將{...}作為一個整體傳遞給該函數。如果沒有定義該函 //數,則由於該類是個非聚合類用{}初始化時,會呼叫建構函式來初始化。 //但由於Foo類不存在3個引數的建構函式,所以f3那行會編譯失敗! Foo f2{77, 5}; //Foo(initializer_list<int> list) Foo f3{77, 5, 42}; //Foo(initializer_list<int> list) Foo f4 = {77, 5}; //Foo(initializer_list<int> list) FooMap fm = {{1,2}, {3,4},{5,6}}; return 0; } /*測試結果: e:StudyC++117>g++ -std=c++11 test2.cpp e:StudyC++117>a.exe Foo(int a, int b) Foo(initializer_list<int> list) : 77 5 Foo(initializer_list<int> list) : 77 5 42 {1,2} {3,4} {5,6} */
到此這篇關於C++11中跳轉initializer_list實現分析的文章就介紹到這了,更多相關C++11 initializer_list內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45