• C++ template 学习归纳2


    关于c++中的类模板,常见的形式为:

    template<typename T>
    class className{
    	//...
    };

    比如笔者在这里举一个例子:

    #include <iostream>
    #include<vector>
    #include <stdexcept>
    
    template<typename T>
    class stack{
    private:
    	std::vector<T> elems;
    public:
    	void push(T const&);
    	void pop();
    	T top() const;
    	bool empty() const{
    		return elems.empty();
    	}
    };
    
    template<typename T>
    void stack<T>::push(T const& a){
    	elems.push_back(a);
    }
    
    template<typename T>
    void stack<T>::pop(){
    	if(elems.empty()){
    		throw std::out_of_range("stack<T>::pop empty");
    	}
    	return elems.pop_back();
    }
    
    template<typename T>
    T stack<T>::top()const{
    	if(elems.empty()){
    		throw std::out_of_range("stack<T>::top empty");
    	}
    	return elems.back();
    }
    
    int main(){
    
    	return 0;
    }

    从上面的代码可以看出,为了定义成员函数,我们使用了下面的形式,比如:

    template<typename T>
    void stack<T>::push(T const& a){
    	elems.push_back(a);
    }

    本来在此处有一个问题的,也就是关于类成员函数的实现位置的问题,这个问题我们稍后会提到。

    现在我们为了测试上面的例子可以使用下面的函数代码:

    int main(){
    	stack<int> intStack;
    	intStack.push(1);
    	intStack.push(2);
    	std::cout<<intStack.top()<<std::endl;
    
    	stack<std::string> strStack;
    	strStack.push("hello");
    	std::cout<<strStack.top()<<std::endl;
    	return 0;
    }

    我们有些时候会遇到这样的代码,比如:

    stack<stack<int> > intStack;

    在这种情况下,我们要注意就是两个“>”中间的那个空格,那个是必须的,否则的话,编译器会认为是“>>”。这一点大家写代码的时候要注意。

    下面我们来看看类模板的特化:

    当我们想特化一个类模板的时候,我们就需要用template<>开头,后面更上我们希望特化的代码。比如:

    template<>
    class myStack<std::string>{
    	//...
    };

    对于特化类模板而言,就如同编写普通的类成员函数一样,比如:

    void myStack<int>::pop(int const& a){
    	//...
    }

    下面我们呢来看看类模板的局部特化。

    例如对于下面的代码:

    template<typename T1,typename T2>
    class myClass{
    	/...
    };

    而言,以下几种像是的局部特化都是正确 的:

    //局部特化 两个参数一致
    template<typename T>
    class myClass<T,T>{
    	//...
    };
    
    //局部特化 第二个为int
    template<typename T>
    class myClass<T,int>{
    	//...
    };
    
    //两个参数都为指针类型
    template<typename T1,typename T2>
    class myClass<T1*,T2*>{
    	//...
    };

    在下面的例子中:

    myClass<int float>mif; //将使用<T1,T2>
    myClass<float,float>mif; //将使用<T>
    myClass<float,int>mif;  //将使用<T,int>
    myClass<int*,double*>mp;  //将使用<T1*,T2*>

    大家要注意下面的错误代码,

    myClass<int,int>m; 
    myClass<int*,int*>m;

    z这两个代码在上面的这个例子中都是错误的。前者因为会和myClass<T,T>产生二义性。后者会和myClass<T,T>产生二义性、使得编译器不知道应该匹配哪一个。

    如果想解决上面的第二个二义性的话,我们可以专门特化下面的代码:

    template<typename T>
    class myClass<T*,T*>{
    	//...
    };

    接下来我们来看看预设模板参数:

    我们先来看看代码再说,大家注意和上面的例子进行比较:

    #include <iostream>
    #include<vector>
    #include <deque>
    #include <cstdlib>
    #include <stdexcept>
    
    template<typename T,typename CONT=std::vector<T> >
    class stack{
    private:
    	CONT elems;
    public:
    	void push(T const&);
    	void pop();
    	T top() const;
    	bool empty() const{
    		return elems.empty();
    	}
    };
    
    template<typename T,typename CONT>
    void stack<T,CONT>::push(T const& a){
    	elems.push_back(a);
    }
    
    template<typename T,typename CONT>
    void stack<T,CONT>::pop(){
    	if(elems.empty()){
    		throw std::out_of_range("stack<T>::pop empty");
    	}
    	return elems.pop_back();
    }
    
    template<typename T,typename CONT>
    T stack<T,CONT>::top()const{
    	if(elems.empty()){
    		throw std::out_of_range("stack<T>::top empty");
    	}
    	return elems.back();
    }
    
    int main(){
    	try{
    		stack<int> intStack;
    		stack<double,std::vector<double> > douStack;
    		//注意,这里千万不能写下面的这一行代码:
    		// stack<double,std::vector<int> > douStack;
    		
    		intStack.push(1);
    		std::cout<<intStack.top()<<std::endl;
    
    		douStack.push(1.1);
    		std::cout<<douStack.top()<<std::endl;
    	}catch(std::exception const& ex){
    		std::cerr<<ex.what()<<std::endl;
    		return EXIT_FAILURE;
    	}
    	return 0;
    }

    我们使用

    	stack<double,std::vector<double> > douStack;

    来声明了一个double stack,他的内部使用的是std:Open-mouthed smileeque<>来管理。

    image

  • 相关阅读:
    SpringCloud面试题
    网工必知:(1)Cisco 路由器PPPOE拨号配置与NAT简单上网配置
    【网工的福利来了!】用Excel表做的“子网划分&路由聚合计算器”
    肝了,一文让你看懂《Docker极简入门指南》
    ImportError: libopenblas.so.0: cannot open shared object file
    Linux软件包管理工具 Snap 常用命令
    squashfs文件系统
    回环设备
    Mac homebrew报错Error: homebrew-core is a shallow clone.
    公钥和私钥
  • 原文地址:https://www.cnblogs.com/rollenholt/p/2383729.html
Copyright © 2020-2023  润新知