ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

decltype,initializer_list,variadic templates学习记录(c++)

2021-02-16 17:33:36  阅读:220  来源: 互联网

标签:templates std tempA decltype int list initializer


decltype,initializer_list,variadic templates

decltype

decltype的作用就是的到一个表达式或者变量的类型

#include <iostream>
using namespace std;

int getSize()
{
    cout << "call getSize()" << endl;
}

int main()
{
    int tempA = 2;
    /*1.dclTempA为int.*/
    decltype(tempA) dclTempA;
    /*2.dclTempB为int,对于getSize根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用getSize().*/
    decltype(getSize()) dclTempB;

    return 0;
}

在这里插入图片描述
并没有调用getSize,只是分析decltype的类型

#include <iostream>
using namespace std;
int main()
{
    int tempA = 0, &refTempA = tempA;
    /*1.dclTempA为引用,绑定到tempA*/
    decltype(refTempA) dclTempA = tempA;
    /*2.dclTempB为引用,必须绑定到变量,编译不过*/
    decltype(refTempA) dclTempB = 0;
    /*3.dclTempC为引用,必须初始化,编译不过*/
    decltype(refTempA) dclTempC;
    /*4.双层括号表示引用,dclTempD为引用,绑定到tempA*/
    decltype((tempA)) dclTempD = tempA;
    
    const int ctempA = 1, &crefTempA = ctempA;
    
    /*5.dclTempE为常量引用,可以绑定到普通变量tempA*/
    decltype(crefTempA) dclTempE = tempA;
    /*6.dclTempF为常量引用,可以绑定到常量ctempA*/
    decltype(crefTempA) dclTempF = ctempA;
    /*7.dclTempG为常量引用,绑定到一个临时变量*/
    decltype(crefTempA) dclTempG = 0;
    /*8.dclTempH为常量引用,必须初始化,编译不过*/
    decltype(crefTempA) dclTempH;
    /*9.双层括号表示引用,dclTempI为常量引用,可以绑定到普通变量tempA*/
    decltype((ctempA))  dclTempI = ctempA;
}
#include <iostream>
using namespace std;
int main()
{
    int tempA = 2;
    int *ptrTempA = &tempA;
    /*1.常规使用dclTempA为一个int *的指针*/
    decltype(ptrTempA) dclTempA;
    /*2.需要特别注意,表达式内容为解引用操作,dclTempB为一个引用,引用必须初始化,故编译不过*/
    decltype(*ptrTempA) dclTempB;
}

在这里插入图片描述
上面图片上的用法应该是一个比较适用的用法了,我们不知道lambda的类型,在容器的声明的时候就可以用decltype,当然这个也可以用function来包裹。

参考博客:https://www.cnblogs.com/ghbjimmy/p/10636030.html

lnitializer_list

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当出现在以下两种情况的被自动构造:
1.当初始化的时候使用的是大括号初始化,被自动构造。包括函数调用时和赋值
2.当涉及到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;
}

另外,initializer_list底部值array容器在做支撑。

Variadic Templates

在这里插入图片描述
上图是使用变参模板来实现printf函数可以传入任意参数,并将参数打印出来,就是通过不断地减少参数,递归的调用printf函数知道后面的参数没有了就输出后面的字符串,上面一个例子就是\n。

另外一个就是找出最大值:
在这里插入图片描述在这里插入图片描述
如果是类型相同的比较大小,上面的方法就能满足,代码也容易懂。

在这里插入图片描述
变参模板的实现:
这样就可以传入任意类型的参数,至于不同类型的参数能不能比大小就看你有没有关于这两种操作符的重载函数了。

这个列子就是如果这第一个参数和最后一个参数有一些特殊的处理,可以看看下一个例子:

在这里插入图片描述
其实可以看见,上面的做法就是在最后的时候进行一个偏特化,这样当tuple只剩最后一个参数时,就会调用到这个函数。

在这里插入图片描述
在这里插入图片描述
第一张构造函数那里的返回类型编译会报错,下面的写法是对的

这个就是tuple的实现,tuple是元组,类似于数据库中一张表中的一条记录。
重点就是在继承:private tuple,这样做就会产生递归的继承,就是图片右边所示,下面就是内存的结构图,这样递归的继承就会把tuple所需要的数据成员构造出来。

在这里插入图片描述
上面的是通过递归的复合来实现tuple的功能,composited m_tail就会递归的复合下去。

参考资料:侯捷老师的视频

标签:templates,std,tempA,decltype,int,list,initializer
来源: https://blog.csdn.net/qq_43812167/article/details/113824621

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有