C++11中初始化列表initializer lists的使用方法
C++11引入了初始化列表來初始化變量和對(duì)象。自定義類型,如果想用初始化列表就要包含initializer_list頭文件。
C++11將使用大括號(hào)的初始化(列表初始化)作為一種通用初始化方式,可用于所有類型。初始化列表不會(huì)進(jìn)行隱式轉(zhuǎn)換。
C++11提供的新類型,定義在<initializer_list>頭文件中。
template< class T >
class initializer_list;
先說它的用處吧,然后再詳細(xì)介紹一下。
首先有了initializer_list之后,對(duì)于STL的container的初始化就方便多了,比如以前初始化一個(gè)vector需要這樣:
int a[] = {0, 1, 2, 3};
std::vector<int> vec(a, a+sizeof(a));
或者
std::vector<int> vec;
vec.push_back(1);
vec.push_back(3);
vec.push_back(3);
vec.push_back(2);
有了initializer_list后,就可以直接像初始化數(shù)組一樣:
class Test { private: static std::map<string, string> const nameToBirthday = { {"lisi", "18841011"}, {"zhangsan", "18850123"}, {"wangwu", "18870908"}, {"zhaoliu", "18810316"}, }; }
當(dāng)然啦,里面的std::map必須提供參數(shù)為initializer_list的構(gòu)造函數(shù)如:
map( std::initializer_list<value_type> init,
const Compare& comp = Compare(),
const Allocator& alloc = Allocator() );
其實(shí)for(initializer: list)中如果list是個(gè)形如:{a, b, c...},那么其實(shí)list自動(dòng)被構(gòu)造成了initializer_list對(duì)象。
下面稍微介紹一下initializer_list
一個(gè)initializer_list當(dāng)出現(xiàn)在以下兩種情況的被自動(dòng)構(gòu)造:
當(dāng)初始化的時(shí)候使用的是大括號(hào)初始化,被自動(dòng)構(gòu)造。包括函數(shù)調(diào)用時(shí)和賦值
當(dāng)涉及到for(initializer: list),list被自動(dòng)構(gòu)造成initializer_list對(duì)象
也就是說initializer_list對(duì)象只能用大括號(hào){}初始化。
拷貝一個(gè)initializer_list對(duì)象并不會(huì)拷貝里面的元素。其實(shí)只是引用而已。而且里面的元素全部都是const的。
下面一個(gè)例子可以幫助我們更好的理解如何使用initializer_list:
#include <iostream> #include <vector> #include <initializer_list> using namespace std; template <class T> struct S { vector<T> v; S(initializer_list<T> l) : v(l){ cout << "constructed with a " << l.size() << "-elements lists" << endl; } void append(std::initializer_list<T> l) { v.insert(v.end(), l.begin(), l.end()); } pair<const T*, size_t> c_arr() const{ return {&v[0], v.size()}; } }; template <typename T> void templated_fn(T arg) { for (auto a : arg) cout << a << " "; cout << endl; } int main() { S<int> s = {1, 2, 3, 4, 5}; //automatically construct a initializer_list // object and copy it s.append({6, 7 , 8}); //list-initialization in function call cout << "The vector size is now " << s.c_arr().second << " ints:" << endl; for (auto n : s.v) cout << ' ' << n; cout << endl; cout << "range-for over brace-init-list: " << endl; for (auto x : {-1, -2, 03}) //// the rule for auto makes this ranged for work cout << x << " "; cout << endl; auto al = {10, 11, 12}; //special rule for auto cout << "The list bound to auto has size() = " << al.size() << endl; //templated_fn({1, 2, 3}); //compiler error! "{1, 2, 3}" is not an expressionit has no type, and so T cannot be duduced. templated_fn<initializer_list<int> > ({7, 8, 9}); //ok templated_fn<vector<int> >({3, 5, 7}); //also ok return 0; }
下面是從其他文章中copy的測試代碼,詳細(xì)內(nèi)容介紹可以參考對(duì)應(yīng)的reference:
#include "init_list.hpp" #include <iostream> #include <vector> #include <map> #include <string> #include <set> /// // reference: http://en.cppreference.com/w/cpp/language/list_initialization struct Foo { //std::vector<int> mem = { 1, 2, 3 }; // list-initialization of a non-static member //std::vector<int> mem2; //Foo() : mem2{ -1, -2, -3 } {} // list-initialization of a member in constructor }; std::pair<std::string, std::string> f(std::pair<std::string, std::string> p) { return{ p.second, p.first }; // list-initialization in return statement } int test_init_list1() { int n0{}; // value-initialization (to zero) int n1{ 1 }; // direct-list-initialization std::string s1{ 'a', 'b', 'c', 'd' }; // initializer-list constructor call std::string s2{ s1, 2, 2 }; // regular constructor call std::string s3{ 0x61, 'a' }; // initializer-list ctor is preferred to (int, char) int n2 = { 1 }; // copy-list-initialization double d = double{ 1.2 }; // list-initialization of a temporary, then copy-init std::map<int, std::string> m = { // nested list-initialization { 1, "a" }, { 2, { 'a', 'b', 'c' } }, { 3, s1 } }; std::cout << f({ "hello", "world" }).first << '\n'; // list-initialization in function call const int(&ar)[2] = { 1, 2 }; // binds a lvalue reference to a temporary array int&& r1 = { 1 }; // binds a rvalue reference to a temporary int // int& r2 = {2}; // error: cannot bind rvalue to a non-const lvalue ref // int bad{1.0}; // error: narrowing conversion unsigned char uc1{ 10 }; // okay // unsigned char uc2{-1}; // error: narrowing conversion Foo f; std::cout << n0 << ' ' << n1 << ' ' << n2 << '\n' << s1 << ' ' << s2 << ' ' << s3 << '\n'; for (auto p : m) std::cout << p.first << ' ' << p.second << '\n'; //for (auto n : f.mem) // std::cout << n << ' '; //for (auto n : f.mem2) // std::cout << n << ' '; return 0; } // reference: https://mbevin.wordpress.com/2012/11/16/uniform-initialization/ int test_init_list2() { int arr[] { 1, 2, 3, 4, 5 }; std::vector<int> v{ 1, 2, 3, 4, 5 }; std::set<int> s{ 1, 2, 3, 4, 5 }; std::map<int, std::string> m{ { 0, "zero" }, { 1, "one" }, { 2, "two" } }; return 0; } /// // reference: https://mbevin.wordpress.com/2012/11/16/uniform-initialization/ // 'aggregate' class - no user-declared constructor, no private/protected members, no base, no virtual function struct ClassA { int x; double y; }; // non-aggregate class class ClassB { private: int x; double y; public: ClassB(int _x, double _y) :x(_x), y(_y) {} }; std::pair<double, double> multiplyVectors( std::pair<double, double> v1, std::pair<double, double> v2) { return{ v1.first*v2.first, v1.second*v2.second }; } int test_init_list3() { int i{ 3 }; int j{}; // empty braces initialize the object to it's default (0) std::string s{ "hello" }; ClassA objA1{}; ClassA objA2{ 1, 2.0 }; ClassB objB1{ 1, 2.0 }; ClassA arrOfAs[] = { { 1, 1.0 }, { 2, 2.0 }, { 3, 3.0 } }; // ouch, the theory is that this should work in C++11, however this doesn't compile, at least with clang, comments? ClassB arrOfBs[] = { { 1, 1.0 }, { 2, 2.0 }, { 3, 3.0 } }; // however, this does work std::vector<ClassB> vectorOfBs = { { 1, 1.0 }, { 2, 2.0 }, { 3, 3.0 } }; auto result = multiplyVectors({ 1.0, 2.0 }, { 3.0, 4.0 }); return 0; }
GitHub: https://github.com/fengbingchun/Messy_Test
接著看一下Blackops同學(xué)的補(bǔ)充
由于最近數(shù)據(jù)結(jié)構(gòu)有個(gè)實(shí)驗(yàn)報(bào)告說是要對(duì)字符串進(jìn)行排序,想偷個(gè)懶不想一個(gè)一個(gè)地賦值,雖然可以用strcpy和傳入二級(jí)指針的形式直接寫,但是這樣感覺不美觀漂亮。
然后就去膜了一下C++11的新特性——初始化列表,概念就不說了,就講下這東西具體怎么用吧,就是正常的寫一個(gè)構(gòu)造函數(shù),然后把參數(shù)改為initializer_list<數(shù)據(jù)類型> &t如圖所示
可以理解為傳入的參數(shù)數(shù)據(jù)被放到了一個(gè)儲(chǔ)存器t中,利用C++11的auto可以直接遍歷這個(gè)儲(chǔ)存器t,然后把遍歷到的值給結(jié)構(gòu)體用。這里用的是char 數(shù)組而不是int是因?yàn)檫@里有一個(gè)問題,如果把initializer_list尖括號(hào)里的類型改為char *,則會(huì)報(bào)錯(cuò),因?yàn)槠胀ǖ?"雙引號(hào)代表的字符串為實(shí)際為const 類型,實(shí)際本身為一個(gè)指針,指向全局const變量中的地址,因此const char *a="123", *b="123",打印a與b的地址會(huì)發(fā)現(xiàn)a與b是相同的,早上就是因?yàn)檫@個(gè)地方百度了一會(huì)兒才明白,另外一個(gè)點(diǎn)就是若聲明的是info數(shù)組,那么顯然要用info的實(shí)例對(duì)象去初始化,因此還要把字符串加上大括號(hào)來形成一個(gè)個(gè)info實(shí)例對(duì)象
下面是完整代碼:
#include <stdio.h> #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); struct info { char name[20]; info() {} info(const initializer_list<const char *> t) { for (auto &item : t) strcpy(name, item); } }; info one[2] = {{"this is one"}, {"this is two"}}; int main(void) { for (auto &it : one) cout << it.name << endl; return 0; }
上面是直接用const指針進(jìn)行初始化,那如果我已經(jīng)有了一個(gè)字符串的二維數(shù)組像這樣:char s[maxn][maxn] = {"1", "2", "3", "4"},那如何賦值呢?顯然把每一個(gè)字符串的首地址的地址傳進(jìn)去即可。
#include <stdio.h> #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 20; char s[N][N] = {"this is one", "this is two", "3", "4"}; struct info { char name[20]; info() {} info(const initializer_list<const char *> t) { for (auto &item : t) strcpy(name, item); } }; info one[2] = {{s[0]}, {s[1]}}; int main(void) { for (auto &it : one) cout << it.name << endl; return 0; }
似乎更多的情況并不是什么用字符串賦值,而是像int、double或者自定義結(jié)構(gòu)體這樣的賦值,那如何從初始化列表中一個(gè)一個(gè)讀取并連續(xù)地賦值到一維或更高維的數(shù)組里呢?這里用到了C++11的另一個(gè)特性,auto 類型,這樣就可以方便地進(jìn)入初始化列表中去
以HDU 1005為例,如果這題用矩陣快速冪做,那么可以參考以下代碼:
#include <stdio.h> #include <iostream> using namespace std; const int N = 2; const int MOD = 7; const int F[3] = {0, 1, 1}; struct Mat { int A[N][N]; Mat() { for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) A[i][j] = 0; } Mat(initializer_list<int> rhs) { auto it = rhs.begin(); for (int i = 0; it != rhs.end(); ++it, ++i) A[i >> 1][i & 1] = *it; } Mat operator*(const Mat &rhs) { Mat c; for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) for (int k = 0; k < N; ++k) c.A[i][j] = (c.A[i][j] + A[i][k] * rhs.A[k][j]) % MOD; return c; } friend Mat operator^(Mat a, int b) { Mat r; for (int i = 0; i < N; ++i) r.A[i][i] = 1; while (b) { if (b & 1) r = r * a; a = a * a; b >>= 1; } return r; } }; int main(void) { int A, B, n; while (~scanf("%d%d%d", &A, &B, &n) && (A || B || n)) { Mat left = { A, B, 1, 0 }; Mat right = { F[2], 0, F[1], 0 }; if (n <= 2) printf("%d\n", F[n]); else { left = left ^ (n - 2); Mat resultMat = left * right; printf("%d\n", resultMat.A[0][0]); } } return 0; }
到此這篇關(guān)于C++11中初始化列表initializer lists的使用方法的文章就介紹到這了,更多相關(guān)initializer lists初始化列表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c語言通過opencv實(shí)現(xiàn)輪廓處理與切割
這篇文章主要介紹了c語言通過opencv實(shí)現(xiàn)輪廓處理與切割,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01關(guān)于C/C++中static關(guān)鍵字的作用總結(jié)
以下是對(duì)C/C++中static關(guān)鍵字的作用進(jìn)行了總結(jié)介紹,需要的朋友可以過來參考下2013-09-09C++ 動(dòng)態(tài)創(chuàng)建按鈕及 按鈕的消息響應(yīng)
這篇文章主要介紹了C++ 動(dòng)態(tài)創(chuàng)建按鈕及 按鈕的消息響應(yīng)的相關(guān)資料,需要的朋友可以參考下2015-06-06C++中的數(shù)字轉(zhuǎn)字符串to_string
這篇文章主要介紹了C++中的數(shù)字轉(zhuǎn)字符串to_string,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11