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

一、模板应用的几种情况

在模板的开发中,经常会遇到一些比较少见的用法,特别是本身对模板开发应用比较少的,可能看到这些用法头就有些蒙圈。这种情况在模板嵌套中比较常见,本篇就是把这些比较少见的用法分析一下,结合前面的一篇“跟我学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;
}

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

四、总结

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

<think>嗯,用户想了解C++中switch case的用法。我得先回忆一下基本结构,然后想想常见的应用场景和注意事项。首先,switch语句的基本语法是switch(表达式),然后case常量表达式,对吧?记得每个case后面要跟break,否则会继续执行下一个case,这叫“case穿透”。可能需要举个例子说明这点。 然后,用户可能是刚开始学C++,所以需要讲得清楚一点。比如,什么时候用switch比if-else更合适?通常是有多个离散值需要判断的时候。比如处理菜单选项或者状态码。 可能还需要提到default的情况,作为默认处理。还有,case后面的值必须是整型或枚举类型,不能是字符串或者其他类型,这点容易出错,要提醒用户。 有没有什么常见的错误呢?比如忘记写break,或者变量声明在case里导致作用域问题。这时候可能需要用大括号包裹代码块,或者把变量定义在switch外部。 然后举一个例子,比如根据星期几输出不同的信息,或者计算成绩等级。例子要简单明了,突出switch的结构和break的重要性。 再想想C++17里的新特性,有没有关于switch的变化?比如初始化语句,可能允许在switch的条件里初始化变量,这样可以限制作用域,但可能用户还没学到,需要确认是否需要提及。 用户的需求可能是想正确使用switch case,避免常见错误,所以重点放在语法结构、break的作用、case穿透的应用场景以及限制条件上。 总结一下,回答的结构应该是:基本语法、执行流程、注意事项、示例代码,可能加上适用场景和常见错误。确保用中文解释清楚,避免使用专业术语过多,必要时用例子辅助说明。</think>在 C++ 中,`switch-case` 是一种多分支选择结构,适用于需要根据一个变量的不同取值执行不同操作的场景。以下是具体用法和注意事项: --- ### 一、基本语法结构 ```cpp switch (表达式) { // 表达式结果必须是整型或枚举类型 case 常量1: 代码块1; break; // 跳出 switch case 常量2: 代码块2; break; // 更多 case... default: // 所有 case 不匹配时执行 默认代码块; } ``` --- ### 二、执行流程 1. 计算 `switch` 后的表达式 2. 从上到下与各个 `case` 后的常量比较 3. 匹配到某个 `case` 后,执行对应的代码块 4. 遇到 `break` 时退出整个 `switch` 结构 5. 若没有匹配项,执行 `default` 代码块(可选) --- ### 三、关键注意事项 1. **必须用 `break` 终止** 若省略 `break`,会继续执行下一个 `case` 的代码(称为 "case穿透") ```cpp switch (x) { case 1: cout << "一"; case 2: // 当 x=1 时会连续输出 "一二" cout << "二"; break; } ``` 2. **仅支持整型表达式** 表达式类型可以是:`int`, `char`, `enum` 等,但**不支持字符串或浮点数** 3. **作用域限制** 若在 `case` 中定义变量,需要用 `{}` 限定作用域: ```cpp switch (x) { case 1: { int y = 10; // 必须用大括号包裹 cout << y; break; } // case 2 无法访问 y } ``` 4. **default 非必需** 没有匹配项且无 `default` 时,`switch` 不执行任何操作 --- ### 四、典型应用场景 1. **菜单选择** ```cpp switch (choice) { case 'A': openFile(); break; case 'B': saveFile(); break; case 'Q': exit(0); break; default: cout << "无效选项"; } ``` 2. **状态机处理** ```cpp enum State { IDLE, RUNNING, ERROR }; switch (currentState) { case IDLE: handleIdle(); break; case RUNNING: startTask(); break; case ERROR: logError(); break; } ``` --- ### 五、与 if-else 的对比 | | switch-case | if-else | |----------|---------------------|-----------------------| | 适用场景 | 离散值、多分支 | 范围判断、复杂条件 | | 执行效率 | 通常更高(跳转表) | 逐个判断 | | 可读性 | 分支清晰 | 灵活但易嵌套复杂 | --- **建议**:当需要处理超过 3 个离散选项时优先考虑 `switch`,但若涉及范围判断(如 `x > 100`)仍需使用 `if-else`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值