混沌 IN C++::Argument Dependent Lookup

难度: rel="File-List" href="file:///C:%5CUsers%5CADMINI%7E1%5CAppData%5CLocal%5CTemp%5Cmsohtml1%5C02%5Cclip_filelist.xml">

知识回顾:

Argument Dependent Lookup(Koenig Lookup)

    当函数调用时,根据参数类型定义所在的命名空间或类域中查找函数名或运算符。如下所示。

    namespace NS

{

        struct A{};

        void f(A);

}

 

int main()

{

    NS::A a;

    f(a);

}

                           

main中,并未在main所在的全局域中给出函数f的定义和声明,但是这段代码仍然可以通过编译,这正是Argument Dependent Lookup规则在起作用,在确认f(a)为函数调用时,编译器便开始实施Argument Dependent Lookup规则。

 

对于模板函数,这种查找规则仍然有效。例如

namespace NS

{

    struct A{};

    template<typename T> void f(T);

}

 

int main()

{

    NS::A a;

    f(a);

}

 

在上面的代码中,如果显示指定NS::f的模板参数会发生什么情况呢?

 

f(a);

 

程序无法编译通过!貌似Argument Dependent Lookup不起作用了?确切地说现在编译器并没有实施这种查找规则。在编译器的眼中,这行语句并不是函数调用,而是被看作了

 

(f < NS::A) > (a);

 

用小于比较fNS::A,然后其结果再与a进行大于比较。导致这种情况是因为的部分没有被看作是显示指定的模板参数,因为在main所在的全局域中,并没有函数模板f的声明,也没有任何信息说明f是函数模板。解决的办法就是

 

NS::f(a);

 

现在编译器从f的声明得知f是函数模板,那么也理所当然的被看作是显示指定模板参数的列表。

 

问题:

    代码如下。

 

    namespace NS1

    {

        struct A{};

        template<typename T> void f(A){}

}

 

namespace NS2

{

    template<int I> void f(NS1::A){}

}

 

int main()

{

    NS1::A a;

    using NS2::f;

 

    f(a);

}

 

思考这段代码,编译器应该如何处理f

1.  编译失败,f无法和NS1::A进行比较。

2.  编译失败,无法匹配NS2::f的参数,需要一个非类型的模板参数。

3.  编译失败,f未定义。

4.  编译成功,调用NS1::f

5.  编译成功,调用NS2::f

6.  编译失败,二义性,有NS1::fNS2::f的候选匹配。

 

 

答案:

    4. 编译成功,调用NS1::f

 

解析过程:

    首先 using-declarationNS2:f 引入到main函数域中,然后对于f(a)这一句,此刻编译器就能识别到f是一个函数模板,确认为显示指定模板参数,接下来就能确认f(a)是函数调用。在确认是函数调用之后,开始命名查找,首先查找到NS2::f,这是由using-declaration引入到main函数域中的。还没完,接下来开始Argument Dependent Lookupa的类型是定义在NS1中的,还需要在NS1中继续查找f,最后找到了NS1::fNS2::f,而NS2::f的模板参数为非类型模板参数。最符合匹配的就只有NS1::f

你可能感兴趣的:(混沌,IN,C++,c++,编译器,struct)