c++学习笔记十(STL容器)

容器

容器(Container)分类
顺序容器(序列容器)Sequence Containervector,list,deque
关联容器 Associative Containermap,set
容器适配器 Container Adapterstack,queue,priority_queue

一.顺序容器(序列容器)Sequence Container

在这里插入图片描述

vector
vector的四种迭代器:
迭代器作用
iterator可修改迭代器 begin() end()
reverse_iterator逆序可修改迭代器 rbegin() rend()
const_iterator不可修改迭代器 cbegin() cend()
const_reverse_iterator逆序不可修改迭代器 crbegin() crend()

vector迭代器的使用:

#include <iostream>
#include <vector>
using namespace std;

void Travesal(const vector<int>& vec){			//定义外部函数用正序迭代器遍历vector
    vector<int>::const_iterator it = vec.cbegin();
    while(it != vec.cend()){
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}

void TravesalReverse(const vector<int>& vec){	//定义外部函数用逆序迭代器遍历vector
    vector<int>::const_reverse_iterator rit = vec.crbegin();
    while(rit != vec.crend()){
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
}
void Travesal2(const vector<int>& vec){			//用自适应变量遍历数组,c++11特有
    for(auto& n:vec){			//若要修改里面元素时,auto必须要用引用类型才能修改本身
        cout << n << " ";		//否则n取的只是vector的副本
    }
    cout << endl;
}
vector<int>& Multipy(vector<int>& vec,int n){				//遍历并整体乘n
    vector<int>::iterator it = vec.begin();
    while(it != vec.end()){
        *it = *it*n;
        ++it;
    }
    return vec;
}
vector<int>& Multipy2(vector<int>& vec,int m){	//遍历并整体乘m,用自适应变量for循环实现
    for(auto n:vec){
        n = n*m;
    }
    return vec;
}

int main(){
    vector<int> vec={1,2,3,4,5,6,7};
    for(int i=0;i!=vec.size();i++){
        cout << vec[i] << " ";
    }
    cout << endl;

    vector<int>::iterator it = vec.begin();					//正序迭代器
    while(it != vec.end()){
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    vector<int>::reverse_iterator rit = vec.rbegin();		//逆序迭代器
    while(rit != vec.rend()){
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;

    for(auto n:vec){										//自适应变量遍历
        cout << n << " ";
    }
    cout << endl;

    Travesal(vec);											//调用外部定义的函数
    TravesalReverse(vec);
    Travesal2(vec);

    Travesal(Multipy(vec,100));
    Travesal(Multipy2(vec,100));
}

运行结果:
在这里插入图片描述
注意:用自适应变量遍历容器时,若要修改容器里的元素,auto必须要用引用类型才能修改本身,否则n只是取的只是vector副本,正常遍历则不用引用类型也可以。

修改vector空间与容量:

#include <iostream>
#include <vector>
using namespace std;

int main(){
    vector<int> vec={1,2,3,4,5,6,7};
    cout << vec.size() << "," << vec.capacity() <<endl;
    vec.resize(10);						//修改size
//    vec.reserve(5);					//修改capacity
    cout << vec.size() << "," << vec.capacity() <<endl;
    vec.resize(5);
//    vec.reserve(6);
    cout << vec.size() << "," << vec.capacity() <<endl;
}

vector其他的具体操作可以参考链接
实现vector和迭代器iterator:
特殊情况看如何重载后缀++(与前缀++做对比)

#include <iostream>
#include <string>
using namespace std;

template<typename T>
class vector{
    T* _data;           	//下划线表示私有成员变量
    size_t _size;          //元素个数
    size_t _capacity;      //容量
public:           //size_t可以提高代码的可移植性,是long的重载,所占字节大小由主机位数所决定
    vector():_data(NULL),_size(0),_capacity(0){}
    void push_back(const T& val){
        ++_size;
        if(NULL == _data){
            ++_capacity;
            _data = new T[_capacity];
        }
        else{
            if(_size>_capacity){		//如果元素数量大于容量,进行扩容
                _capacity*=2;
                T* temp = new T[_capacity];
                for(int i=0;i<_size-1;++i){
                    temp[i] = _data[i];
                    }
                delete [] _data;
                _data = temp;
                }
            }
        _data[_size-1] = val;
    }
    int size()const{ return _size;}
    int capacity()const{return _capacity;}
    T& operator[](int index){
        return _data[index];
    }

    //qie tao lei :lei zhong ding yi de lei
    class iterator{
        T* _p;
    public:
        iterator(T* p):_p(p){};
        T& operator*(){ return *_p;}
        T* operator->(){ return _p;}
        iterator operator++(){
            ++_p;
            return *this;
        }
        bool operator==(const iterator& it)const{
            return _p == it._p;
        }
        bool operator!=(const iterator& it)const{  //只有上面的双等号重载过后==才可以引用
            return !(*this == it);				   //==才可以引用
//            return _p != it._p;                  //等价于
        }
        iterator operator+(int n)const{
            return iterator(_p+n);
        }
        iterator operator-(int n)const{
            return iterator(_p-n);
        }
        iterator operator++()const{					//前缀++运算符重载
            return iterator(++_p);
        }
        iterator operator++(int)const{				//后缀++运算符重载,int相当于占位符
            iterator tmp(_p);						//创建一个临时对象用来返回
            ++_p;
            return tmp;
        }
        iterator operator--()const{
            return iterator(--_p);
        }
        iterator operator--(int)const{
            iterator tmp(_p);
            --_p;
            return tmp
        }
    };

    iterator begin(){
        return iterator(_data);     //本质就是实例化一个迭代器对象,对象里包含着元素的地址
    }                               //并将这个元素的地址传出去
    iterator end(){
        return iterator(_data+_size);
    }
};

class Student{                      //定义一个学生类进行测试
public:
    string name;
    int age;
};

int main(){
    vector<int> vec;
    for (int i = 0; i < 20; ++i) {
        vec.push_back(i);
        cout << "size:" << vec.size() << ",capcity:" << vec.capacity() << endl;
    }
    for (int j = 0; j < vec.size(); ++j) {
        cout << vec[j] << " ";
    }
    cout << endl;

    vector<int>::iterator it = vec.begin();
    while(it != vec.end()){
        cout << *it << endl;
        ++it;                   //重载的是前加 ,这里的本质是重载对象的成员函数
    }                           //而对象本身不能自加
    cout << endl;
    for(auto n:vec){
        cout << n << " ";
    }
    cout << endl;

    vector<Student> vec1;           	//注意这里的定义的模板的类类型如何初始化定义
    vec1.push_back({"zhangsan",21});	//类似于初始化结构体
    vec1.push_back({"lisi",23});
    vec1.push_back({"wangwu",20});
    
    vector<Student>::iterator it1 = vec1.begin();
    while(it1 != vec1.end()){
        cout << it1->name << "," << it1->age << endl;      //调用符号 -> 的重载函数 
        ++it1;
    }
    cout << endl;
}
list列表
list也有四种迭代器
迭代器作用
iterator可修改迭代器 begin() end()
reverse_iterator逆序可修改迭代器 rbegin() rend()
const_iterator不可修改迭代器 cbegin() cend()
const_reverse_iterator逆序不可修改迭代器 crbegin() crend()

list使用迭代器:

#include <iostream>
#include <list>

using namespace std;

void Travelsal(const list<int>& l){		//迭代器遍历list写在外部函数,使用不可修改迭代器
    list<int>::const_iterator it = l.cbegin();//形参设置为常量引用,防止函数内部修改传对象
    while(it != l.cend()){				//这样函数既可以接受常量对象也可以结束非常量对象
        cout << *it << " ";
        it++;
    }
    cout << endl;
}

void TravelsalReverse(const list<int>& l){
    list<int>::const_reverse_iterator rit = l.crbegin();
    while(rit != l.crend()){
        cout << *rit << " ";
        rit++;
    }
    cout << endl;
}

int main(){
    list<int> l = {1,2,3,4,5};

    for(auto n:l){
        cout << n << " ";
    }
    cout << endl;
    for(int i=0;i<l.size();i++){
//        cout << l[i] << " ";              			//列表不接受下标访问
    }
    cout << endl;

    list<int>::iterator it = l.begin();					//正序迭代器
    while(it != l.end()){
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    list<int>::reverse_iterator rit = l.rbegin();		//倒序迭代器
    while(rit != l.rend()){
        cout << *rit << " ";
        rit++;
    }
    cout << endl;
    Travelsal(l);										//调用外部函数
    TravelsalReverse(l);
}

运行结果:
在这里插入图片描述

list的增删改操作

添加list尾元素:

    l.push_back(6);
    l.push_back(7);
    l.push_back(8);
    Travelsal(l);

在这里插入图片描述

删除list尾元素:

    l.pop_back();
    l.pop_back();
    l.pop_back();

在这里插入图片描述

添加list头元素(list特有):

    l.push_front(-2);
    l.push_front(-1);
    l.push_front(0);
    Travelsal(l);

在这里插入图片描述
删除list头元素(list特有):

    l.pop_front();
    l.pop_front();
    l.pop_front();

在这里插入图片描述

在第二个位置上插入100:

    it = l.begin();
//    it = it+1             //list迭代器不能做算数运算,但是可以自加自减
    ++it;					//因为对象it中运算符++重载过了
    l.insert(it,100);
    Travelsal(l);

在这里插入图片描述

删除100:(因为添加100后,it会指向100后的那个元素,所以要向前移动一位)

    --it;
    l.erase(it);
    Travelsal(l);

在这里插入图片描述

批量添加:

    it = l.begin();
    ++it;
    l.insert(it,5,100);

在这里插入图片描述

批量删除:

    list<int>::iterator first = l.begin();
    ++first;
    l.erase(first,it);
    Travelsal(l);

在这里插入图片描述

插入数组:(之所以插在第二元素开始的位置,是因为it之前所停留在那个位置)

    int arr[] = {11,12,13,14};
    l.insert(it,arr,arr+4);
    Travelsal(l);

在这里插入图片描述

list中插入向量vec:

    vector<int> vec = {21,22,23,24};
    l.insert(l.end(),vec.begin(),vec.end());
    Travelsal(l);

在这里插入图片描述

随机访问:

    it = next(l.begin(),4);
    *it = 10000;
    Travelsal(l);

在这里插入图片描述
list特有成员函数:
倒序输出:

    l.reverse();
    Travelsal(l);

在这里插入图片描述
排序:

    l.sort();
    Travelsal(l);

在这里插入图片描述
指定值删除元素:

    l.remove(10000);
    Travelsal(l);

在这里插入图片描述
实现list和迭代器iterator:

#include <iostream>
#include <exception>
using namespace std;

namespace miniSTL{				//定义一个小型标准模板库的命名空间
    template<typename T>
    class list{
        struct Node{			//list(链表)的节点存储结构为结构体
            T val;
            Node* prev;
            Node* next;
            Node(const T& val):val(val),prev(NULL),next(NULL){}
        };
        Node* head,*tail;
        int _size;
    public:
        list():head(NULL),tail(NULL),_size(0){}			//构造函数
        ~list(){										//析构函数
            while(NULL != head){
                Node* next = head->next;
                delete head;
                head = next;
            }
        void push_back(const T& val){
            ++_size;
            Node* node = new Node(val);
            if(NULL == head){
                head = tail =node;
            }
            else{
                tail->next = node;
                tail = node;
            }
        }
        int size(){
            return _size;
        }
        T& operator[](int index){
            int count = 0;
            Node* p = head;
            while(NULL != p){
                if(count++ ==index) break;
                p = p -> next;
            }
            return p->val;
        }

        class iterator{						//类中类,定义迭代器
            Node* p;
        public:
            iterator(Node* p):p(p){};
            T& operator*(){
                return p->val;
            }
            T* operator->(){
                return &(p->val)
            }
            iterator operator++(){
                p=p->next;
                return *this;
            }
            iterator operator++(int){		//运算符重载后缀++
                iterator tmp(*this);  		//初始化一个临时对象
                p=p->next;
                return tmp;
            }
            iterator operator--(){
                p=p->prev;
                return *this;
            }
            iterator operator--(int){       //运算符重载后缀--
                iterator tmp(*this);        //初始化一个临时对象
                p=p->prev;
                return tmp;
            }
            bool operator==(const iterator &it)const{
                return p == it.p;
            }
            bool operator!=(const iterator &it)const{
                return p != it.p;
            }
        };
        iterator begin(){return iterator(head);}
        iterator end(){ return iterator(NULL);}
    };
}

using namespace miniSTL;
int main(){
    list<int> li;
    li.push_back(1);
    li.push_back(2);
    li.push_back(3);

    cout << li.size() << endl;
    for (int i = 0; i < li.size(); ++i) {
        cout << li[i] << endl;
    }

    list<int>::iterator it = li.begin();				//测试迭代器
    while(it != li.end()){
        cout << *it << endl;
        ++it;
    }
    for(auto n:li){										//测试++重载
        cout << n << endl;			//因为只有重载++实现后,自适应变量循环才可以使用
    }
}
关于vector和list的构造函数定义
#include <iostream>
#include <vector>

using namespace std;

void Print(const vector<int>& vec){
    for(auto n:vec){
        cout << n << " ";
    }
    cout << endl;
}

int main() {
    vector<int> empty;								//默认构造空容器
    Print(empty);
    vector<int> fault(10);							//初始化为10个0元素
    Print(fault);
    vector<int> fault2(10, 2);						//初始化为10个2元素
    Print(fault2);
    vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9};	//显式初始化
    vector<int> vec1 = vec;							//拷贝构造函数
    Print(vec1);
    vector<int> vec2(vec.begin(), next(vec.begin(), 6));	//部分构造
    Print(vec2);

    vec2 = vec1;									//赋值
    Print(vec2);
    vec2 = {10, 11, 12, 13, 14};
    Print(vec2);
    vec2.assign(next(vec1.begin(), 6), vec1.end());
    Print(vec2);
}

对于list和vector有相同的构造函数

emplace_back可以直接使用构造函数的参数,在函数内部执行对象的构造:
在这里插入图片描述

二.关联容器 Associative Container

set(集合)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
示例:

#include <iostream>
#include <set>

using namespace std;

void Print(const set<int>& s){
    for(auto n:s){
        cout << n << " ";
    }
    cout << endl;
}

int main(){
    set<int> s = {10,2,2,2,13,4,15,6};
    Print(s);

    s.insert(-1);
    Print(s);
    s.insert(-1);						//验证值唯一,只能插入一个-1
    s.insert(-1);
    Print(s);

    auto it = s.rbegin();
    while(it != s.rend()){				//倒序输出
        cout << *(it++) << ",";
    }
    cout << endl;
    cout << s.size() << endl;

    s.erase(-1);
    Print(s);
}

统计集合中元素个数:

	cout << s.count(3) << endl;
    cout << s.count(4) << endl;

在这里插入图片描述
查找集合中指定元素:

	auto it3 = s.find(3);
    cout << (it3 == s.end()) << endl;
    auto it4 = s.find(4);
    cout << *it4 <<endl;
//    *it4 = 100;					禁止修改

在这里插入图片描述
set存放的对象必须可以比较大小,所以类必须重载:

class Simple{
public:
    bool operator==(const Simple&)const{
        return true;

    }
    bool operator<(const Simple&)const{
        return true;
    }
};
int main(){
    set<Simple> ss;
}

集合元素之间实现排序:

#include <set>
#include <vector>
#include <iostream>
#include <string>
using namespace std;

template <class T>
void Print(const T& s){		//定义一个打印的模板函数
    for(auto n:s){
        cout << n << " ";
    }
    cout << endl;
}

class Greator{	//定义一个普通整型集合排序的类,返回值为布尔型决定两元素之间需不需要交换位置
public:
        bool operator()(int a,int b){
            return a > b;
        }
    };

class Student{
        string name;
        int age;
        float scores;
public:
        Student(const string& name,int age,float scores):name(name),age(age),scores(scores){}
        int GetAge()const{return age;}
        float GetScores()const{return scores;}
        friend ostream& operator<<(ostream& os,const Student& s){
            return os << s.name << ',' << s.age << ',' << s.scores;
        }
};
    
class AgeCom{		//定义按年龄排序的仿函数类,返回值为布尔型决定两元素之间需不需要交换位置
public:
    bool operator()(const Student& a,const Student& b){
        return a.GetAge() > b.GetAge();
    }
};

class ScoreComp{	//定义按分数排序的仿函数类,返回值为布尔型决定两元素之间需不需要交换位置
public:
    bool operator()(const Student& a,const Student& b){
        return a.GetScores() > b.GetScores();
    }
};

int main() {
    set<int, Greator> s;

    s = {10,2,2,2,13,4,15,6};

    Print(s);

    set<Student,AgeCom> stu = {
            Student("zhangsan",21,89),
            Student("lisi",19,78),
            Student("wangwu",20,69)
    };
    Print(stu);
    set<Student,ScoreComp> stu2(stu.begin(),stu.end());
    Print(stu2);
}

复习函数指针:

项目核心思想
C语言面向过程编程
函数指针函数式编程
c++语言面向对象编程
模板泛型编程
#include <iostream>
#include <vector>
using namespace std;

void Display(int& n){
    cout << n << " ";
}
void Double(int& n){
    n*=n;
}

typedef void (*func_t)(int& n);	//定义一个返回类型为空,参数列表为整型引用的函数指针func_t
void Travesal(vector<int>& vec,func_t func){
    for(auto& n:vec){
        func(n);
    }
}

int main(){
    vector<int> vec = {1,2,3,4,5,6};
    Travesal(vec,Display);
    cout << endl;

    Travesal(vec,Double);
    Travesal(vec,Display);
    cout << endl;
}

模板替换函数指针

#include <iostream>
#include <vector>
#include <list>
#include <set>
using namespace std;

template <typename T>
void Display(T& n){
    cout << n << " ";
}
//void Double(int& n){
//    n*=n;
//}

//typedef void (*func_t)(int& n);		//这里应用了模板自动推导类型,已经用不到函数指针了
template <typename T,typename F>		//这里属于自动推导参数类型
void Travesal(T& vec,F func){
    for(auto n:vec){
        func(n);
    }
}

int main(){
    vector<int> vec = {1,2,3,4,5,6};
    Travesal(vec,Display<int>);			//参数只传个函数名即可,真正的调用在函数内部
    cout << endl;

//    Travesal(vec,Double);
    Travesal(vec,Display<int>);
    cout << endl;

    vector<float> vec2 = {1,1,2,2,3,3,4,4,5,5,6,6};
    Travesal(vec2,Display<float>);

    list<int> li = {1,2,3,4,5,6};
    Travesal(vec2,Display<float>);
    cout << endl;
    
    set<int> s = {1,2,3,4,5,6};
    Travesal(s,Display<int>);
    cout << endl;
}

仿函数的应用:

#include <iostream>
#include <vector>
#include <list>
#include <set>
using namespace std;

template <typename T>
void Display(T& n){
    cout << n << " ";
}
template<typename T>							//定义一个仿函数模板类
class CDisplay{									//类中只有一个()运算符重载函数
public:
    void operator()(T& n)const{
        cout << n << " ";
    }
};
template <typename T,typename F>		//定义的函数模板,传入参数时自动推导类型
void Travesal(T& vec,F func){
    for(auto n:vec){
        func(n);
    }
}

int main(){
    vector<int> vec = {1,2,3,4,5,6};
    Travesal(vec,Display<int>);
    cout << endl;

    Travesal(vec,Display<int>);
    cout << endl;

    vector<float> vec2 = {1,1,2,2,3,3,4,4,5,5,6,6};
    Travesal(vec2,Display<float>);

    list<int> li = {1,2,3,4,5,6};
    Travesal(vec2,Display<float>);
    cout << endl;

    set<int> s = {1,2,3,4,5,6};
    Travesal(s,Display<int>);
    cout << endl;

    int n = 100;
    Display(n);

    CDisplay<int> display;
    display(n);					//一般的仿函数:类名+()重载函数

    CDisplay<int>()(n);			//CDisplay()(n),CDdisply()属于类名,(n)调用的是运算符
    							//重载成员函数,这个类是匿名构造的
    Travesal(s,display);
    Travesal(s,CDisplay<int>());			//这里只是属于构造一个匿名对象,在Travesal函
							//数内部定义了func(n),从而实现仿函数CDisplay<int>()(n)的调用
    Travesal(s,[](int n){cout << n << ',';});
}

说明一:
template <typename T,typename F>
void Travesal(T& vec,F func)
定义的是模板函数,调用函数Travesal时,传入两个参数,会根据参数的类型进行自动推导
说明二:
如果F func传入的是一般函数的函数名,推导的就是指针类型,因为函数名代表的是函数的首地址
说明三:
CDisplay<int display;
display(n);
这里最经典的仿函数,实例化一个对象,对象调用()运算符重载的成员函数,外形像一个函数,实际不是,它等价于display.operator()(n);而display(n)只是它的简写形式
说明四:
Travesal(s,display);
这里的display传入的不是函数名,而是对象名,所以编译器会自动推导为CDisplay类,而在Travesal函数中的func(n)会自动转换成为仿函数调用,因为display()的()在类中重载过了,这和一般函数名做参数有本质的区别
说明五:
CDisplay<int()(n);
这里的CDisplay构造了一个匿名对象,然后再调用()的运算符重载成员函数,也属于仿函数的调用
说明六:
Travesal(s,CDisplay());
这里传入的是一个这里的CDisplay构造的一个匿名对象,然后经过Travesal函数内部func(n),相当于匿名对象的仿函数CDisplay<int()(n),它等价于CDisplay<int()operator()(n);
说明七:
[](int n){cout << n << ‘,’;
这里是Lambada表达式

map(映射关系)

在这里插入图片描述

#include <map>
#include <iostream>
#include <string>
using namespace std;

int main(){
    map<string,string> dict = {					//键值对存储形式
            {"Apple","pinguo"},
            {"Orange","juzi"},
            {"Banana","xiangjiao"}
    };

    cout << dict["Apple"] << endl;				//只能通过前面查找后面,反之不可以
    if(dict.count("xiangjiao") == 1){
        cout << dict["xiangjiao"] << endl;		//如果查询不到,则创建一个新的键值对
    }
    for(auto p :dict){
        cout << p.first << "," << p.second << endl;			//循环遍历输出
    }
}

在这里插入图片描述
map修改:

	dict["Orange"] = "chengzi";
	for(auto p :dict){
       cout << p.first << "," << p.second << endl;
    }

在这里插入图片描述
map插入:

	dict.insert(pair<string,string>("cherry","yintao"));	//插入函数(手动输入类型)
    dict.insert(make_pair("cherries","chelizi"));			//插入模板函数(自动推导)
    dict.insert(pair<string,string>("cherry","yintao2"));	//插入相同的键值无效,并不会增加新的元素

键值对pair的存储结构本质为结构体模板:

	template<typename T,typename S>
	struct pair{
    	T first;
    	S second;
	};

map按键查找:

	map<string,string>::iterator it = dict.find("banana");
    if(it != dict.end()){
        cout << it ->first << " " << it->second << endl;
    }

在这里插入图片描述
map按键删除:

	dict.erase("Apple");
    for(auto p :dict){
        cout << p.first << "," << p.second << endl;
    }

在这里插入图片描述
map中元素的顺序并不是按照插入的顺序排列的,而是map结构有一套自己的排序算法

三.容器适配器 Container Adapter

stack(栈)

示例代码:

#include <iostream>
#include <stack>
#include <vector>

using namespace std;
int main(){
    stack<int> s;
    for (int i = 0; i < 10; ++i) {
        s.push(i);
    }
    cout << "size" << s.size() <<endl;

    while(!s.empty()){
        cout << s.top() << endl;
    }
//不可以使用迭代器
//不能随机访问[]
//不能使用for(auto n:s)

//将vector转成stack
    vector<int> vec = {1,2,3,4,5};
    stack<int,vector<int>> s1(vec);

    vector<int> res;
    while(!s1.empty()){
        res.push_back(!s1.empty());
        s1.top();
    }
    for(auto m:res){
        cout << m << " ";
    }
    cout << endl;
}

模板函数中使用静态变量和嵌套类中变量的特殊情况
typename的第二种用法

#include <iostream>

using namespace std;

class Simple{
public:
    static int Static;
    class Test{};
    typedef int Number;   
};
int Simple::Static = 0;	//类中的静态成员变量要在类外定义
template <typename T>
void Func(T& s){
    T::Static;	//模板认为类名(T::XXXX)只是在访问类的静态成员变量,而不是使用嵌套类定义的对象
    typename T::Test n;		//如果在模板中使用类里面定义的类型,必须在前面加上关键字typename
    typename T::Test num;	//这是typename的第二个作用,第一个作用是在声明模板的类型时使用
}

int main(){
    Simple::Static;
    Simple::Test n;//在非模板里面可以直接使用,不需要加上关键字typename
					//类里面的静态成员变量和类内部类型的访问方式是一样的,类名::XXXX
    Simple::Number num;
    Simple s;
    Func(s);
}
模板函数迭代器的统一以及获取首尾元素的模板函数
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <algorithm>

using namespace std;

namespace MiniSTL{

	//模板函数迭代器的统一
    template <typename T>
    typename T::iterator begin(T& c){	//iterator是T类中的嵌套类,所以在实例化它的时候
        return c.begin();				//要用关键字typename声明,告诉编译器T::iterator
    }									//是一个类型,而不是在初始化静态变量
    template <typename T>
    typename T::iterator end(T& c){
        return c.end();
    }
    template <typename T,size_t N>			//偏特化
    T* begin(T (&arr)[N]){
        return arr;
    }
    template <typename T,size_t N>			//偏特化
    T* end(T (&arr)[N]){
        return arr+N;
    }
    
	//获取首尾元素的模板函数
    template <typename T>
    typename T::value_type front(T& c){
        return *c.begin();
    }
    template <typename T>
    typename T::value_type back(T& c){
        typename T::iterator e = c.end();
        --e;
        return *e;
    }
    template <typename T,size_t N>
    T front(T (&arr)[N]){
        return arr[0];
    }
    template <typename T,size_t N>
    T back(T (&arr)[N]){
        return arr[N-1];
    }
}

int main(){
    vector<int> vec = {1,2,3,4,5};				//定义vector
    for_each(vec.begin(),vec.end(),[](int n){cout << n << " ";});
    cout << endl;
    set<int> s = {1,2,3,4,5};					//定义set
    for_each(s.begin(),s.end(),[](int n){cout << n << " ";});
    cout << endl;
    list<int> li = {1,2,3,4,5};					//定义list
    for_each(li.begin(),li.end(),[](int n){cout << n << " ";});
    cout << endl;
    int arr[] = {1,2,3,4,5};					//定义一个数组
    for_each(arr,arr+5,[](int n){cout << n << " ";});
    cout << endl;

	//测试迭代器的模板函数
    for_each(MiniSTL::begin(vec),MiniSTL::end(vec),[](int n){cout << n << " ";});
    cout << endl;
    for_each(MiniSTL::begin(s),MiniSTL::end(s),[](int n){cout << n << " ";});
    cout << endl;
    for_each(MiniSTL::begin(li),MiniSTL::end(li),[](int n){cout << n << " ";});
    cout << endl;
    for_each(MiniSTL::begin(arr),MiniSTL::end(arr),[](int n){cout << n << " ";});
    cout << endl;

	//测试获取首尾元素
    cout << MiniSTL::front(vec) << "," << MiniSTL::back(vec) <<endl;
    cout << MiniSTL::front(li) << "," << MiniSTL::back(li) <<endl;
    cout << MiniSTL::front(s) << "," << MiniSTL::back(s) <<endl;
    cout << MiniSTL::front(arr) << "," << MiniSTL::back(arr) <<endl;
}

模板函数中使用静态变量和类中变量的特殊情况:

#include <iostream>

using namespace std;

class Simple{
public:
    static int Static;
    class Test{};
    typedef int Number;   
};
int Simple::Static = 0;	//类中的静态成员变量要在类外定义
template <typename T>
void Func(T& s){
    T::Static;	//模板认为类名(T::XXXX)只是在访问类的静态成员变量,而不是使用嵌套类定义的对象
    typename T::Test n;		//如果在模板中使用类里面定义的类型,必须在前面加上关键字typename
    typename T::Test num;	//这是typename的第二个作用,第一个作用是在声明模板的类型时使用
}

int main(){
    Simple::Static;
    Simple::Test n;//在非模板里面可以直接使用,不需要加上关键字typename
					//类里面的静态成员变量和类内部类型的访问方式是一样的,类名::XXXX
    Simple::Number num;
    Simple s;
    Func(s);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值