[C++ Template]深入模板--模板中的名称

本文深入探讨了C++模板中的名称分类和查找机制,包括Argument-Dependent Lookup (ADL)、友元名称插入、插入式类名称等。文章详细阐述了模板解析过程中依赖型类型名称和依赖型模板名称的处理,以及在派生和类模板中的特殊情况,揭示了C++模板机制的复杂性和灵活性。
摘要由CSDN通过智能技术生成

目录

9 模板中的名称

9.1 名称分类

9.2 名称查找

9.2.1 Argument-Dependent Lookup(ADL)

9.2.2 友元名称插入

9.2.3 插入式类名称

9.3 解析模板

9.3.2 依赖型类型名称

9.3.3 依赖型模板名称

9.3.4 using-declaration中的依赖型名称

9.3.5 ADL和显式模板实参

9.4 派生和类模板

9.4.1 非依赖型基类

9.4.2 依赖型基类


9 模板中的名称

实现者的角度出发, 就名称而言, C++是一门相当棘手的语言。 譬如 C++语句x*y, 如果x和y都是变量的名称, 那么这个语句代表一个乘积; 但如果x是一个类型的名称, 那么这个语句声明y是一个指向类型为x的实体的指针。

这个小例子说明了C++(与C一样) 是一种上下文相关语言: 对于C++的一个构造, 我们不能脱离它的上下文来理解它。 但这又和模板有哪些联系呢? 事实上, 模板也是一种构造, 它必须处理多种上下文相关信息: (1) 模板出现的上下文; (2) 模板实例化的上下文; (3) 用来实例化模板的模板实参的上下文。 因此, 在C++中, 小心处理各种(上下文的) 名称的做法就不足为奇了。
 

9.1 名称分类

C++使用了多种多样的方法来对名称进行分类。 为了有助于理解名称的众多术语。 幸运的是, 你只需要熟悉下面两个主要的命名概念, 就可以深入理解大多数模板话题:
(1) 如果一个名称使用域解析运算符(即: : ) 或者成员访问运算符(即 .或->) 来显式表明它所属的作用域, 我们就称该名称为受限名称。 例如, this->count就是一个受限名称, 而count则不是(即使前面没有符号, count实际上引用的也是一个类成员) 。

(2) 如果一个名称(以某种方式) 依赖于模板参数, 我们就称它为依赖型名称。 例如, 如果T是一个模板参数, std::vector<T>::iterator就是一个依赖名称; 但如果T是一个已知的typedef(类型定义, 例如int) , 那么std::vector<T>::iterator就不是一个依赖名称。

 

9.2 名称查找

受限名称的名称查找是在一个受限作用域内部进行的, 该受限作用域由一个限定的构造所决定。 如果该作用域是一个类, 那么查找范围可以到达它的基类; 但不会考虑它的外围作用域。 下面的例子说明了这些基本原则:

int x;
class B 
{
public:
	int i;
}; 

class D : public B {
};
void f(D* pd)
{
	pd->i = 3; //找到B::i
	D::x = 2; //错误: 并不能找到外围作用域中的::x
}

非受限名称的查找则相反, 它可以(由内到外) 在所有外围类中逐层地进行查找(但在某个类内部定义的成员函数定义中, 它会先查找该类和基类的作用域, 然后才查找外围类的作用域) , 这种查找方式也被称为普通查找。 下面的例子说明普通查找的一些基本概念:

extern int count; //(1)
int lookup_example(int count) //(2)
{
	if (count < 0) 
	{
		int count = 1; //(3)
		lookup_example(count); //非受限的count将会引用(3)
	} 
	return count + ::count; //第1个(非受限的)count引用(2),第2个(受限的) count引用(1)
}

对于非受限名称的查找, 最近增加了一项新的查找机制——除了前面的普通查找——就是说非受限名称有时可以使用依赖于参数的查找(argument-dependent lookup, ADL) 。 在阐述ADL的细节之前, 让我们先通过前面的max()模板来说明这种机制的动机:

template <typename T>
inline T const& max(T const& a, T const& b){
	return a < b ? b : a;
}

假设我们现在要让“在另一个名字空间中定义的类型”使用这个模板函数:

namespace BigMath 
{
	class BigNumber 
	{
		...
	};

	bool operator < (BigNumber const&, BigNumber const&);
	...
} 

using BigMath::BigNumber;
void g(BigNumber const& a, BigNumber const& b)
{
	...
		BigNumber x = max(a, b);
	...
}

问题是 max()模板并不知道 BigMath 名字空间, 因此普通查找也找不到“应用于BigNumber 类型值的 operator<”。 如果没有特殊规则的话,这种限制将会大大减少 C++名字空间中模板的应用。 ADL正是这个特殊规则, 也正是解决这种限制的关键之处。

 

9.2.1 Argument-Dependent Lookup(ADL)

ADL只能应用于非受限名称。 在函数调用中, 这些名称看起来像是非成员函数。 对于成员函数名称或者类型名称, 如果普通查找能找到该名称, 那么将不会应用ADL。 如果把被调用函数的名称(如max) 用圆括号括起来, 也不会使用ADL。否则, 如果名称后面的括号里面有(一个或多个) 实参表达式, 那么ADL将会查找这些实参的associated class(关联类) 和associatednamespace(关联名字空间) ,稍后给出二者的定义。但从直观上来看, 我们可以认为是: 与给定类型直接相关的所有namespace和class。 例如, 如果某一类型是指向class X的指针, 那么它的associated class和associated
namespace会包含X和X所属的任何class和namespace。

对于给定类型, 对于由associated class和associated namespace所组成的集合的准确定义, 我们可以通过下列规则来确定

•对于基本类型, 该集合为空集。

•对于指针和数组类型, 该集合是所引用类型(譬如对于指针而言, 它所引用的类型是“指针所指对象”的类型) 的associated class和associated namespace。

•对于枚举类型, associated namespace指的是枚举声明所在的namespace。 对于类成员, associated class指的是它所在的类。

•对于class类型(包含联合类型) , associated class集合包括: 该class类型本身、 它的外围类型、 直接基类和间接基类。 associated namespace 集合是每个 associated class 所在的namespace。 如果这个类是一个类模板实例化体, 那么还包含: 模板类型实参本身的类型、 声明模板的模板实参所在的class和namespace。

•对于函数类型, 该集合包括所有参数类型和返回类型的associated class 和associated namespace。

对于类X的成员指针类型, 除了包括成员相关的associated anmespace和associated calss, 该集合还包括与X相关的associated namespace和associated class。

至此,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值