千家信息网

C++11中初始化列表initializer lists怎么用

发表于:2025-02-06 作者:千家信息网编辑
千家信息网最后更新 2025年02月06日,这篇文章给大家分享的是有关C++11中初始化列表initializer lists怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。C++11引入了初始化列表来初始化变量
千家信息网最后更新 2025年02月06日C++11中初始化列表initializer lists怎么用

这篇文章给大家分享的是有关C++11中初始化列表initializer lists怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

C++11引入了初始化列表来初始化变量和对象。自定义类型,如果想用初始化列表就要包含initializer_list头文件。

C++11将使用大括号的初始化(列表初始化)作为一种通用初始化方式,可用于所有类型。初始化列表不会进行隐式转换。

C++11提供的新类型,定义在头文件中。

template< class T >
class initializer_list;

先说它的用处吧,然后再详细介绍一下。

首先有了initializer_list之后,对于STL的container的初始化就方便多了,比如以前初始化一个vector需要这样:

int a[] = {0, 1, 2, 3};
std::vector vec(a, a+sizeof(a));

或者

std::vector 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 const nameToBirthday = {        {"lisi", "18841011"},        {"zhangsan", "18850123"},        {"wangwu", "18870908"},        {"zhaoliu", "18810316"},    };}

当然啦,里面的std::map必须提供参数为initializer_list的构造函数如:

map( std::initializer_list 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 #include #include using namespace std;template struct S {    vector v;    S(initializer_list l) : v(l){        cout << "constructed with a " << l.size() << "-elements lists" << endl;    }    void append(std::initializer_list l) {        v.insert(v.end(), l.begin(), l.end());    }    pair c_arr() const{        return {&v[0], v.size()};    }};template void templated_fn(T arg) {    for (auto a : arg)        cout << a << " ";    cout << endl;}int main() {    S 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 > ({7, 8, 9}); //ok    templated_fn >({3, 5, 7});           //also ok    return 0;}

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "init_list.hpp"#include #include #include #include #include  ///// reference: http://en.cppreference.com/w/cpp/language/list_initializationstruct Foo {        //std::vector mem = { 1, 2, 3 }; // list-initialization of a non-static member        //std::vector mem2;        //Foo() : mem2{ -1, -2, -3 } {} // list-initialization of a member in constructor}; std::pair f(std::pair 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 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 v{ 1, 2, 3, 4, 5 };        std::set s{ 1, 2, 3, 4, 5 };        std::map 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 functionstruct ClassA {        int x;        double y;}; // non-aggregate classclass ClassB {private:        int x;        double y;public:        ClassB(int _x, double _y) :x(_x), y(_y) {}}; std::pair multiplyVectors(        std::pair v1,        std::pair 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 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同学的补充

由于最近数据结构有个实验报告说是要对字符串进行排序,想偷个懒不想一个一个地赋值,虽然可以用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 #include 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 pii;typedef long long LL;const double PI = acos(-1.0);struct info{    char name[20];    info() {}    info(const initializer_list 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 #include 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 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 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 #include 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 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怎么用"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

0