模板中的名称
1.受限名称的查找:在一个受限的作用域内部进行查找。
2.非受限名称:A:查找则相反由内向外类中进行查找,注意会先查找该类和基类的作用域。
B:对与非限制名称,增加了ADL 查找机制即可以按照参数的查找。
C:对于成员函数名称和类型名称,按普通 方法查找。
D:如果被调用的函数名用括号括起来如(max)() 使用ADL查找。
代码:
#include <iostream>
namespace X{
class A
{
public:
int z;
};
A a;
template<typename T> void f(T)
{
std::cout<<"X::f(X::E) called\n"; ;
}
}
namespace N
{
enum E{e1};
void f(E)
{
std::cout<<"N::f(N::E) called\n";
}
}
void f( int )
{
std::cout<<"::f(int) called \n";
}
int _tmain(int argc, _TCHAR* argv[])
{
::f(N::e1); //受限域不进行ADL(依赖参数查找),结果::f(int) called;
f(N::e1); //进行ADL 查找N::f(N::E) called;
(f)(N::e1);//不按照ADL查找 ::f(int) called
f(X::a ); //进行ADL 查找 X::f(X::E) called;
return 0;
}
3.插入式类名称
(1)定义:如果在类的本身的作用域中插入该类的名称,我们就称该名称为插入式类名称。
(2)类模板中也可以具有插入式类名称。
template<template<typename > class TT > class X{};
template<typename T > class C
{
C* a; //
C<void> b;
X<C> C; //错误:后面咩有模板参数的列表的c不被看做模板
x< ::C > e;
};
从上面的代码我们可以知道 如果这些非受限名称的后面没有紧跟模板实参,将不会被看做模板名称开看待。为了避免这种情况应该在模板名称前面加上作用域限定符::.
4.依赖类型名称
主要问题:依赖类型名称不能在模板里面得到有效的确定,特别是模板里面不能引用其他模板的名称,原因:其他模板的内容可能由于显示特化使原来的名称得到失效。
解决方法:
C++ 语言通过上下文约定解决这个问题,依赖型受限名称并不代表一个名称。除非在这个名称前面加上typename.
使用typename 的规则:
1.名称出现在类模板中
2.名称是受限的
3.名称没有出现在基类继承列表中,也不是位于引入构造函数的成员列表中
4.名称依赖于模板参数。
满足前面三个必须加上typename.
总结:
受限名称出现在类模板中,只要没有出现在类模板的继承列表和构造函数列表中就需要添加他也typename.
5.依赖型模板名称
定义:如果一个模板名称是一个依赖型名称。
解决方法:
想让编译器知道所引用的名称是一个模板,需要在名称前面加上template.
6.using-declaration中的依赖 型名称
规则:
1.想要编译器知道名称是一个类型名称,需要在名称名称加上typename.
2.C++ 并没有提供一种标准机制,来指定依赖型名称是一个模板。
7.派生和类模板
1.非依赖型基类:无需知道模板实参就可以完全确定类型的基类。
名字查找的区别:
非依赖型基类和普通模板类中的基类的区别:模板中的非异类型基类,在它的派生类中查找一个非受限名称,就会查找这个非依赖型的基类,然后查找模板参数列表。
2.依赖型基类
c++:非依赖型名称不会在依赖型基类中进行查找,为了解决这个问题(可以进非依赖型改为依赖型的,因为依赖型的只有到实例化的时候才会被查找。)
解决方法:
1.this->f();
2.Basic<T>::f(),对于虚函数会受到限制。
总结:
对于模板类中的属性,或者成员函数中的参数使用Basic<T> 加上限定(因为没有办法对于Enum来使用this->来使用)。