• 【c++ templates读书笔记】【4】技巧性基础知识


    1、关键字typename

    引入关键字typename是为了说明:模板内部的标识符可以是一个类型。当某个依赖与模板参数的名称是一个类型时,就应该使用typename。

    template<T>
    class MyClass{
    	typename T::SubType * ptr;  // typename说明SubType是定义于T内的一种类型,如果不使用typename,SubType会被认为是T的一个静态成员
    	...
    };
    

    2、使用this->

    对于那些在基类中声明,并且依赖于模板参数的符号(函数或变量等),应该在它们前面使用this->或者Base<T>::。

    #include<iostream>
    using namespace std;
    
    template<typename T>
    class Base{
    public:
    	void exit(){ cout << "exit" << endl; }
    };
    template<typename T>
    class Derived:Base<T>{
    public:
    	void exitDerived(){
    		this->exit();//但VS 2013中直接用exit()也能正确运行
    	}
    };
    int main(){
    	Derived<int> d;
    	d.exitDerived();
    
    	system("pause");
    	return 0;
    }
    

    3、成员模板

    嵌套类和成员函数都可以作为模板,例子:
    #include<iostream>
    #include<deque>
    using namespace std;
    
    template<typename T>
    class Stack{
    private:
    	deque<T> deq;
    public:
    	void push(T const& elem);
    	void pop();
    	T top() const;
    	bool empty() const{
    		return deq.empty();
    	}
    	template<typename T2>//成员模板
    	Stack<T>& operator=(Stack<T2> const& op2);
    };
    template<typename T>
    void Stack<T>::push(T const& elem){
    	deq.push_back(elem);
    }
    template<typename T>
    void Stack<T>::pop(){
    	if (deq.empty()){
    		throw out_of_range("Stack<>::pop():empty stack");
    	}
    	deq.pop_back();
    }
    template<typename T>
    T Stack<T>::top() const{
    	if (deq.empty()){
    		throw out_of_range("Stack<>::pop():empty stack");
    	}
    	return deq.back();
    }
    template<typename T>
    template<typename T2>
    Stack<T>& Stack<T>::operator=(Stack<T2> const& op2){
    	if ((void*)this == (void*)&op2)
    		return *this;
    	Stack<T2> tmp(op2);
    	deq.clear();
    	while (!tmp.empty()){
    		deq.push_front(tmp.top());
    		tmp.pop();
    	}
    	return *this;
    }
    
    int main(){
    	try{
    		Stack<float> istk;
    		istk.push(7.2);
    		istk.push(8.3);
    		istk.push(9.4);
    		cout << istk.top() << endl;
    		istk.pop();
    		cout << istk.top() << endl;
    
    		Stack<int> sstk;
    		sstk = istk;
    		cout << sstk.top() << endl;
    		sstk.pop();
    		cout << sstk.top() << endl;
    	}
    	catch (exception const& ex){
    		cerr << "Exception:" << ex.what() << endl;
    		return EXIT_FAILURE;
    	}
    
    	system("pause");
    	return 0;
    }
    

    4、模板的模板参数

    模板参数本身是模板,则该参数是模板的模板参数。函数模板不支持模板的模板参数。

    例子:

    #include<iostream>
    #include<deque>
    #include<vector>
    using namespace std;
    //这里Container是模板的模板参数
    template<typename T,template<typename ELEM,typename=allocator<ELEM>> class Container=deque>
    class Stack{
    private:
    	Container<T> container;
    public:
    	void push(T const& elem);
    	void pop();
    	T top() const;
    	bool empty() const{
    		return container.empty();
    	}
    	template<typename T2, template<typename ELEM2, typename = allocator<ELEM2>> class Container2>
    		Stack<T, Container>& operator=(Stack<T2, Container2> const& op2);
    };
    template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
    void Stack<T,Container>::push(T const& elem){
    	container.push_back(elem);
    }
    template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
    void Stack<T, Container>::pop(){
    	if (container.empty()){
    		throw out_of_range("Stack<>::pop():empty stack");
    	}
    	container.pop_back();
    }
    template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
    T Stack<T, Container>::top() const{
    	if (container.empty()){
    		throw out_of_range("Stack<>::pop():empty stack");
    	}
    	return container.back();
    }
    template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
    template<typename T2, template<typename ELEM2, typename = allocator<ELEM2>> class Container2>
    Stack<T, Container>& Stack<T, Container>::operator=(Stack<T2, Container2> const& op2){
    	if ((void*)this == (void*)&op2)
    		return *this;
    	Stack<T2, Container2> tmp(op2);
    	container.clear();
    	while (!tmp.empty()){
    		container.push_front(tmp.top());
    		tmp.pop();
    	}
    	return *this;
    }
    
    int main(){
    	try{
    		Stack<double> dstk;
    		dstk.push(7.2);
    		dstk.push(8.3);
    		dstk.push(9.4);
    		cout << dstk.top() << endl;
    		dstk.pop();
    		cout << dstk.top() << endl;
    
    		Stack<int> istk;
    		istk = dstk;
    		cout << istk.top() << endl;
    		istk.pop();
    		cout << istk.top() << endl;
    	}
    	catch (exception const& ex){
    		cerr << "Exception:" << ex.what() << endl;
    		return EXIT_FAILURE;
    	}
    
    	system("pause");
    	return 0;
    }
    

    5、使用字符串作为函数模板的实参

    #include<iostream>
    #include<string>
    using namespace std;
    
    template<typename T>
    T const& Max(T const& a, T const& b){
    	return a < b ? b : a;
    }
    
    int main(){
    	string s = "abc";
    
    	cout << Max("apple", "peach") << endl;
    	//cout << Max("apple", "tomato") << endl;//错误,不同类型的实参
    	//cout << Max("apple", s) << endl;//错误,不同类型的实参
    
    	system("pause");
    	return 0;
    }
    

    上述例子在VS2013中运行错误。

    上述例子中后面两个调用错误的问题在于:由于长度的区别,这些字符串属于不同的数组类型,”apple”和”peach”具有相同的类型char const[6],”tomato”的类型是char const[7],因此只有第一个调用合法。但声明的是非引用参数,可以使用不同的字符串作为参数。

    #include<iostream>
    #include<string>
    using namespace std;
    
    template <typename T>
    T Max(T a, T b){
    	return  a < b ? b : a;
    }
    
    int main(){
    	string s = "abc";
    
    	cout << Max("apple", "peach") << endl;
    	cout << Max("apple", "tomato") << endl;//正确,退化为相同的类型
    	//cout << Max("apple", s) << endl;//错误,不同类型的实参
    
    	system("pause");
    	return 0;
    }
    

    上述第二个调用正确,原因是对于非引用类型的参数,在实参演绎的过程中,会出现数组到指针的类型转换。但是这里比较的是指针,而不是两个字符串的字典序。


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    【转载】zookeeper数据模型
    java.util.logging使用笔记2
    spark提交应用的方法(spark-submit)
    spark集群模式概述
    [spark]spark 编程教程
    [spark]Spark Streaming教程
    使用github pages创建博客
    spark 编程教程
    Spark编程指南V1.4.0(翻译)
    mysql基本操作
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4921345.html
Copyright © 2020-2023  润新知