0.简介
C++语言的名称搜寻机制设计众多细节,我们只集中在数个主要概念上,为了保证:
1)通常情况下,这些查询符合人们的直觉;
2)特别复杂的情况可以在C++standard中找到答案。
受饰名称的查询范围是在其“修饰构件所处的作用域”(the scope implied by the qualifying construct)内。如果该作用域是个class,则其base class也将被查询。然而编译器查询受饰名称时,并不考虑圈封作用域enclosing scopes。下面的例子阐释了这个基本法则:
int x;
class B{
public:
int i;
};
class D: public B{};
void f(D* pd)
{
pd->i =3; //编译器找到B::i(pd->i 是个 qualified name)
D::x =2; //Error, 在D作用域中(包括B)也找不到x
}
与之形成对比的是,编译器通常会依次在更外层的圈封作用域(more enclosing scopes)中查询非受饰名称unqualified names,尽管在成员函数定义内编译器会先查询class作用域和base class作用域,然后才是其他圈封作用域。这便是所谓的ordinary lookup(常规查询)。
下面例子展示ordinary lookup的基本概念:
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; //第一个count(非受饰)代表(2)
//第二个::count(受饰)代表(1)
}
在常规查询之外,还有一种用法来查询非受饰名称unqualified names.这种机制有时也称为依赖于实参的查询,argument-dependent lookup,ADL。深入ADL之前,先介绍要给引发此机制的例子:
template <typename T>
inline T const & max (T const&, a, T const& b)
{
return a<b ? b:a;
}
现在假设我们需要把这个template应用到定义于另一个namespace内的类型身上:
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() template 对BigMath namespace一无所知,而ordinary lookup常规查询机制无法找到一个operator < 可施行于BigNumber类型。如果没有某种特殊规则,这个问题就大大缩减了templates在C++ namespaces 情形下的应用性。一个解决办法就是ADL。
1.依赖于实参的查询Argument-Dependent Lookup, ADL
ADL只适用于这样的非受饰名称unqualified names:在函数调用动作中用到的一个非成员函数名称。如果ordinary lookup可找到一个成员函数名称或一个类型名称,编译器就不启动ADL。如果被调用函数的名称被写进一对小括号内,ADL也不起作用。
#include <iostream>
namespace X {
template<typename T> void f(T);
}
namespace N {
using namespace X;
enum E {e1};
void f(E) {
std::cout << "N::f(N::E) called" << std::endl;
}
}
void f(int)
{
std::cout << "::f(int ) called" << std::endl;
}
int main()
{
::f(N::ee1); //受饰函数名称,不使用ADL
f(N::e1); // ordinary lookup,找到::f,而ADL找到N::f(),编译器会优先考虑后者
}
这个例子中, ADL机制中的namespace N中的using指令被忽略。因此main()中的f()不会被编译器认为是对X::f()调用。
2.友元名称植入Friend Name Inject
3. 植入类名称Injected Class Names