不可思议:using namespace无效!(3)

来源:互联网 发布:好用的浏览器 知乎 编辑:程序博客网 时间:2024/05/16 05:58

不可思议: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.

 (完)