不可思议:using namespace无效!(3)
C++ namespace与name lookup之惑
续
不可思议:using namespace无效!(1)
不可思议:using namespace无效!(2)
std空间中已定义的operator<造成了这个错误,这是以上测试得出的猜想。
stl里面pair定义最简单,stl_pair.h也不包含其它头文件,其中就有一个operator<,
所以 #include <bits/stl_pair.h> 试试,确实有问题。
再试试自定义一个operator<,让问题彻底清晰化。
class testClass
{
};
namespace test
{
bool operator<( const testClass &class1,
const testClass &class2 )
{
return true;
}
};
using namespace test;
namespace std001 // or std
{
struct my_pair
{
};
bool operator<(const my_pair & x,
const my_pair & y)
{
return true;
}
void testCompare(const testClass & t1,
const testClass & t2)
{
if (t1 < t2) // Fail: no match '<'
;
}
}
main()
{
testClass t1, t2;
std::testCompare(t1, t2);
}
这样就可以清楚地看到问题:
In function `void std001::testCompare(const testClass&, const testClass&)':
no match for 'operator<' in 't1 < t2'
candidates are: bool std001::operator<(const std001::my_pair&, const std001::my_pair&)
果然是"std001::operator<"造成了问题。
但是为什么会这样,为什么对"test::operator<"视而不见?
难道using namespace test;无效?
试试using test::operator<;是有效的,那么
using namespace test; // error?
using test::operator <; // OK!
两者不能等效?
为了解释这个问题,必须先了解C++名字查找的相关概念。
搜索“C++ name lookup”可以找到此概念,如“GotW#30”就是对此概念的解释与例子。
当然“GotW#30”没有提出上述的问题,也没有对上述问题的提示。
What is koenig lookup?
主要是解释“koenig lookup(ADL)”的,同时也解释了“Ordinary name lookup(OL)”.
简单地说,名字查找分为两部分,一是“koenig lookup”,
也称为argument-dependent name lookup(ADL),即根据参数查找,
二是“Ordinary name lookup”,从最近的作用域开始查找。
但请注意这段文字:OL terminates as soon as the name is found。
OL可能找到的是错误的。
这就是上述代码所表现出来的问题。
std001::testCompare会在其参数所在空间查找operator<, 但并没有定义。
如果operator<与类testClass定义于同一命名空间则可利用ADL正确找到定义。
std001::testCompare在最近的作用域找到了std001::operator<,结果是错误的。
为什么对test::operator<视而不见?是否using namespace test;无效?
不是无效,是名字查找过程退出的原因.
这个OL错误问题更早的在一篇文章" C++ Lookup Mysteries"由Sven Rosvall描述并解释,
他的代码例子稍复杂,不容易看到问题所在,但他的解释却充分详实的多。
using namespace test; // error?
using test::operator <; // OK!
两者等效吗?
确实不等效。
“using namespace test” is using-Directive,
“using test::operator<” is using-Declaration.
“using test::operator<” means '<' is fully-qualified name.
(完)