模板基础(1)

member template

  • 所谓成员模板就是一个类的成员函数是模板。类似下面这样:
template <class T>
class Stack{
private:
vector<T> v_;

template <class T2>
Stack<T>& operator=(const Stack<T2>&); //类内声明
};

template <class T>	//类外实现
template <class T2>
Stack<T> Stack<T>::operator=(const Stack<T2>& st){
	...
}
  • 可以看到成员模版的语法:在函数上面再来一层template,类似模板函数的声明。而它的实现就是将使用的template逐层写出,然后再来实现。
  • 你可能会问,这有什么用?
 template <class _InputIterator>
  list(_InputIterator __first, _InputIterator __last,
       const allocator_type& __a = allocator_type())
    : _Base(__a)
    { insert(begin(), __first, __last); 
  • 上面就是SGI下容器list的关于迭代器的构造函数。可以看到使用了迭代器。所谓的_InputIterator就是输入型迭代器,这来源于STL的命名风格:参数的命名使用接口可以接纳的最弱的迭代器。
  • 这使得我们可以使用vector等一系列容器构造list,只要它的迭代器强于_InputIterator。
  • 成员模板一个显著的作用就是支持容器的隐式类型转换,没错是容器的。
template<class T>
class Stack{
private:
std::vector<T> v_;
public:
	void pop();
	void push(const T&);
	 T& top();
	std::size_t size()const;
	bool empty();
	Stack();
	Stack<T>& operator=(const Stack<T>&);
};

Stack<int> intSt;
intSt.push(1);
Stack<float> floatSt;
floatSt.push(2.22);
intSt = floatSt; // error !
  • 上面的最后一行代码会出现问题,即使float可以隐式转换成int,但是Stack不可以隐式转换成Stack。因为没有这样的operator=函数。没错,有了上面的栗子,你应该很快能反映过来!我需要operator的右操作数的类型是更高阶的可变!
  • 这就轮到成员模板大显身手了。
template<class T>
class Stack{
	//其他的不变;注意,原先的operator=已被删除!!
template<class T2>
	Stack<T>& operator=(const Stack<T2>&);
};
  • 上面的operator=就是一个成员模板函数,它支持隐式类型转换。而且你不需要保留老版本的operator=来应付非隐式类型转换,因为当两个Stack = Stack进行转换时,T和T1都会被推导成int。
  • 现在你的Stack = Stack会被成功编译。

模板的模板形参

  • 模板的形参既可以是type,non-type,也可以是模板。
  • 没错,像下面这样,
template<class T, template<class T2> class _Con = std::deque>
class Stack{
private:
_Con<T> c_;
	...
};
  • 可以看到第一行中有3个class,第一个class正常声明模板类型参数,而第二个class代表_Con这个模板形参需要的模板形参(细细品品,可能有点绕)!!这两个class都可以被typename替换,但是第三个class表示_Con是一个类名!!不能被typename替换!
  • 依据此,我们可以重写Stack类。
template<class T, template<class EL> class _Con = std::deque>
class Stack {
private:
	_Con<T> _c;
public:
	void pop();
	void push(const T&);
	bool empty();
	std::size_t size();
	T& top();
template<typename T2,template<typename,typename> class _Con2>
	Stack<T, _Con>& operator= (const Stack<T2, _Con2>&);
};

  • 但是,你会发现编译不过去。因为我们的deque默认有两个模板形参,第二个正是我们的空间配置器,虽然它有缺省实参,但是模板的模板参数再传参是,编译器会忽略缺省实参!我们需要显式的写出模板参数来。
  • 据此,我们可以写出一个包含成员模板和模板的模板参数的Stack类。
template<class T, template<class EL, class = std::allocator<EL>> class _Con = std::deque>
class Stack {
private:
	_Con<T> _c;
public:
	void pop();
	void push(const T&);
	bool empty();
	std::size_t size()const;
	T& top();
template<typename T2,template<typename,typename> class _Con2>
	Stack<T, _Con>& operator= (const Stack<T2, _Con2>&);
};

template<class T, template<class, class> class _Con>
void Stack<T, _Con>::pop() {
	_c.pop_back();
}

template<class T, template<class, class> class _Con>
void Stack<T, _Con>::push(const T& tmp) {
	_c.push_back(tmp);
}

template<class T, template<class, class> class _Con>
bool Stack<T, _Con>::empty() {
	return _c.empty();
}

template<class T, template<class, class> class _Con>
std::size_t Stack<T, _Con>::size()const {
	return _c.size();
}

template<class T, template<class, class> class _Con>
  T& Stack<T, _Con>::top() {
	return _c.back();
}

template<class T, template<class, class> class _Con>
template<class T1, template<class, class> class _Con1>
Stack<T, _Con>& Stack<T, _Con>::operator=(const Stack<T1, _Con1>& rhs) {
	if ((void*)&rhs == (void*)this) {  //证同测试
		return *this;
	}
	Stack<T1, _Con> tmp(rhs);
	_c.clear();
	while (!tmp.empty()) {
		_c.push_front(tmp.top());
		tmp.pop();
	}
	return *this;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值