跟我学c++中级篇——模板嵌套中的依赖限定

238 篇文章 98 订阅

一、模板应用的几种情况

在模板的开发中,经常会遇到一些比较少见的用法,特别是本身对模板开发应用比较少的,可能看到这些用法头就有些蒙圈。这种情况在模板嵌套中比较常见,本篇就是把这些比较少见的用法分析一下,结合前面的一篇“跟我学c++中级篇——模板的模板参数和成员模板”一起学习,会有更好的领悟。

二、几种符号的在模板依赖限定中的作用

在一些模板的源码中可以看到类似“->template”、“::template”、“.template”用法,比如“DW::template Write((typename U::DataType)v)”,直观上第一印象会是,这三个运算符“->,.和 ::”不是限定域的么?对,它就是做限定的,在模板中的应用也是如此。明白这一点很重要,正如在前面学习重载operator运算时,提到过的一句话,“重载运算符的意义尽量要和运算符本身保持一致”,举一个例子,重载了一个“+”加法运算符,却是用的乘法规则,这就不好。但是,从语法意义上又没有问题,就是这个意思。

三、依赖限定符的说明

先看一个<C++ Templates The Complete Guide> 2th中( 13.3.3节),一个例程:

template<typename T>
class Shell {
public:
template<int N>
class In {
public:
template<int M>
class Deep {
public:
virtual void f();
};
};
};

template<typename T, int N>
class Weird {
 public:
 void case1 (
 typename Shell<T>::template In<N>::template Deep<N>* p) {
 p->template Deep<N>::f(); // inhibit virtual call
 }
 void case2 (
 typename Shell<T>::template In<N>::template Deep<N>& p) {
 p.template Deep<N>::f(); // inhibit virtual call
 }
 };

“p->template Deep::f()”,用到了“->”后面还有一个“p.template”,而“typename Shell::template In::template Deep”又出现了“::template”(说明,typename表示::后的为类型,详情可参考相关书籍),它和前在的例子,“DW::template Write((typename U::DataType)v)”都是类和函数限定的方式。
当此类限定符前面的名称或者表达式类型依赖于模板参数,可能会引起未知的特化,并且此时限定符后的名称为模板标识时,就会使用上述的方式来进行依赖限定说明。
在上面的这个例子中,p类型依赖于模板参数T(typename Shell ==》 template<typename T, int N>),编译器无法确定Deep是个模板类,所以需要使用template这个关键字来显示的指示出依赖限定。否则编译器就会将其解析为“((p.Deep)<n)>f()”。这和上面小括号中对typename的限定增加是一样的,前者确定是类型,后者告诉编译器是模板。
再看一个函数的例子:

#include <iostream>

void run() {
	std::cout << "call function run()" << std::endl;
}

template<typename T>
class Example {
public:
	template <int N = 10>
	void run() {
		std::cout << "Example member function run(): " << N << std::endl;
	}
};

template<typename T>
class Sub : public Example<T>
{
public:
	Sub(T t) :mt() {}
	void callrun0() { run(); }							 // 全局 f()
	void callrun1() { /*this->template run();*/ this->run(); }		 //注释为G++,默认为VC
	void callrun2() { Example<T>::template run(); }		 
	void callrun3() { Example<T>::template run<3>(); }	 
	void callrun4() { ::run(); }
private:
  	T mt;					 
};

int Test()
{
	Sub<int> s(7);
	s.callrun0();
	s.callrun1();
	s.callrun2();
	s.callrun3();
	s.callrun4();

	return 0;
}

这里是一个函数限定的应用,对比着一看就更明白了。

四、总结

“遇到问题不要慌,先拍个照,发个朋友圈”。遇到问题时,需要冷静的联想相关的知识,然后再有针对性的查找相关资料。说一句不太准确的话,在大多数人的认知体系中,几乎所有的知识都是有传承体系的,不会突然出现,遇到一些不太清楚的用法,也不要着急,因为要明白,学习的知识是已有的,而不是需要你去创造的。否则,就是发明家了。学习还是有技巧有方法可以掌握的。
好好学习,天天向上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值