//############################################################################
/*
* Koenig Lookup / Argument Dependent Lookup (ADL)
*/
// 例1: 什么是Koenig查找
namespace A
{
struct X {};
void g( X ) { cout << " calling A::g() \n"; }
}
// void g( X ) { cout << " calling A::g() \n"; } //如果再加一个函数,会编译不过
int main() {
A::X x1;
A::g(x); //正常
g(x1); // 移除A::并不会报错,会到实参所在的命名空间查找
}
// 例2:
class C {
public:
struct Y {};
static void h(Y) { cout << "calling C::h() \n"; }
};
int main() {
C::Y y;
h(y); // Error Koenig查找只对命名空间有效,对类无效
}
// 例3:
namespace A
{
struct X {};
void g( X ) { cout << " calling A::g() \n"; }
}
class B {
void g(A::X ) { cout << "calling B::g() \n" ; }
};
class C : public B {
public:
void j() {
A::X x;
g(x);
}
};
int main() {
C c;
c.j(); //没有歧义,先在类中查找,没找到再去global和Koenig查找
}
// 名字隐藏的情况:命名空间的例子
namespace A
{
struct X {};
void g(X ) { std::cout << " calling A::g() \n"; }
namespace C {
void g( ) { std::cout << "calling C:g() \n" ; }
void j() {
//using A::g;
g(8); //编译不过,名字遮蔽
X x;
g(x); //Koenig原则同样有效
}
}
}
int main() {
A::C::j();
}
/*
* 名字查找顺序
*
* 命名空间:
* 当前作用域 => 外面一层作用域 => ... => 全局作用域
*
* 要覆写顺序:
* 1. 使用限定符或者using声明
* 2. Koenig lookup
*
* 类:
* 当前类作用域 => 父类作用类 => ... => 全局域
*
* 要覆写顺序::
* - 使用限定符或者using声明
*
*
* 名字隐藏
* 当高层作用域定义了和低层作用域相同名字的函数
*/
/*
* 为啥要有Koenig Lookup?
*/
// 例1:
namespace A
{
struct X {};
void g( X ) { cout << " calling A::g() \n"; }
void g( ) { cout << " calling A::g() \n"; }
}
int main() {
A::X x1;
g(x1); // Koenig Lookup, or Argument Dependent Lookup (ADL)
g(); // Error
}
/*
* 1. 实际原因
*/
std::cout << "Hi.\n"; // 这里的数据运算符会调用 std::operator<<,而不用显式指定
std::cout std::<< "Hi.\n"; // 如果没有Koenig查找,要写成这种形式,编译不过
std::operator<<(std:cout, "Hi,\n"); //正确的写法
/*
* 2. 理论原因:
* -- 什么是类的接口?
*/
namespace A
{
class C {
public:
void f() = 0;
void g() = 0;
};
void h(C); //是C的接口的一部分
ostream& operator<<( ostream&, const C& ); //是C的接口的一部分
}
void j(C); //不就是C的接口的一部分
/*
* 类的定义:
* 类是描述一组数据以及操作这些数据的函数的集合。
*/
/*
* 工程上的原则:
* 1. 对C类进行操作且跟C在同一个命名空间的函数是C的接口的一部分
* 2. 所以作为C的接口的一部分的函数需要在同一个命名空间下
*/
A::C c;
c.f(); //可以直接调用
h(c); //可以直接调用
namespace A {
class C {};
int operator+(int n, A::C) { return n+1; } //如果放在外面可能会出现问题,万一std命名空间中定义了其他函数,就不会找到这个函数
}
int main()
{
A::C arr[3];
std::accumulate(arr, arr+3, 0); // return 3
}
// 定义在C++标准库<numeric>
namespace std {
template <class InputIterator, class T>
T accumulate ( InputIterator first, InputIterator last, T init )
{
while ( first!=last )
init = init + *first++;
return init;
}
}