您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關C++11中初始化列表initializer lists怎么用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
C++11引入了初始化列表來初始化變量和對象。自定義類型,如果想用初始化列表就要包含initializer_list頭文件。
C++11將使用大括號的初始化(列表初始化)作為一種通用初始化方式,可用于所有類型。初始化列表不會進行隱式轉換。
C++11提供的新類型,定義在<initializer_list>頭文件中。
template< class T >
class initializer_list;
先說它的用處吧,然后再詳細介紹一下。
首先有了initializer_list之后,對于STL的container的初始化就方便多了,比如以前初始化一個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后,就可以直接像初始化數組一樣:
class Test { private: static std::map<string, string> const nameToBirthday = { {"lisi", "18841011"}, {"zhangsan", "18850123"}, {"wangwu", "18870908"}, {"zhaoliu", "18810316"}, }; }
當然啦,里面的std::map必須提供參數為initializer_list的構造函數如:
map( std::initializer_list<value_type> init,
const Compare& comp = Compare(),
const Allocator& alloc = Allocator() );
其實for(initializer: list)中如果list是個形如:{a, b, c...},那么其實list自動被構造成了initializer_list對象。
下面稍微介紹一下initializer_list
一個initializer_list當出現在以下兩種情況的被自動構造:
當初始化的時候使用的是大括號初始化,被自動構造。包括函數調用時和賦值
當涉及到for(initializer: list),list被自動構造成initializer_list對象
也就是說initializer_list對象只能用大括號{}初始化。
拷貝一個initializer_list對象并不會拷貝里面的元素。其實只是引用而已。而且里面的元素全部都是const的。
下面一個例子可以幫助我們更好的理解如何使用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的測試代碼,詳細內容介紹可以參考對應的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
由于最近數據結構有個實驗報告說是要對字符串進行排序,想偷個懶不想一個一個地賦值,雖然可以用strcpy和傳入二級指針的形式直接寫,但是這樣感覺不美觀漂亮。
然后就去膜了一下C++11的新特性——初始化列表,概念就不說了,就講下這東西具體怎么用吧,就是正常的寫一個構造函數,然后把參數改為initializer_list<數據類型> &t如圖所示
可以理解為傳入的參數數據被放到了一個儲存器t中,利用C++11的auto可以直接遍歷這個儲存器t,然后把遍歷到的值給結構體用。這里用的是char 數組而不是int是因為這里有一個問題,如果把initializer_list尖括號里的類型改為char *,則會報錯,因為普通的""雙引號代表的字符串為實際為const 類型,實際本身為一個指針,指向全局const變量中的地址,因此const char *a="123", *b="123",打印a與b的地址會發現a與b是相同的,早上就是因為這個地方百度了一會兒才明白,另外一個點就是若聲明的是info數組,那么顯然要用info的實例對象去初始化,因此還要把字符串加上大括號來形成一個個info實例對象
下面是完整代碼:
#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指針進行初始化,那如果我已經有了一個字符串的二維數組像這樣:char s[maxn][maxn] = {"1", "2", "3", "4"},那如何賦值呢?顯然把每一個字符串的首地址的地址傳進去即可。
#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或者自定義結構體這樣的賦值,那如何從初始化列表中一個一個讀取并連續地賦值到一維或更高維的數組里呢?這里用到了C++11的另一個特性,auto 類型,這樣就可以方便地進入初始化列表中去
以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; }
感謝各位的閱讀!關于“C++11中初始化列表initializer lists怎么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。