简体   繁体   English

关于在进行不合格调用时使用名称与使用命名空间的歧义

[英]About the ambiguity of using a name vs using a namespace when doing unqualified calls

I knew that this would be ambiguous我知道这会模棱两可

#include <boost/hana/fwd/equal.hpp>
#include <range/v3/algorithm/equal.hpp>
#include <vector>

int main() {
    std::vector<int> v{1,2,3};
    using namespace boost::hana;
    using namespace ranges;
    equal(v, v);
}

because there's an equal both in boost::hana and ranges namespaces.因为boost::hanaranges命名空间是equal的。

However, I thought this would be ambiguous too:但是,我认为这也很模棱两可:

#include <boost/hana/fwd/equal.hpp>
#include <range/v3/algorithm/equal.hpp>
#include <vector>

int main() {
    std::vector<int> v{1,2,3};
    using namespace boost::hana;
    using ranges::equal;
    equal(v, v);
}

But that's not the case, according to GCC and Clang .但根据GCC 和 Clang ,情况并非如此。

Why is that?这是为什么?

Snippet 2片段 2

Lets look at how the second snippet in your example works since you already know the reason for why the first snippet produces ambiguous error.让我们看看示例中的第二个代码段是如何工作的,因为您已经知道第一个代码段产生不明确错误的原因。

From Using directives' documentation :来自使用指令的文档

Using-directives are allowed only in namespace scope and in block scope. From the point of view of unqualified name lookup of any name after a using-directive and until the end of the scope in which it appears, every name from namespace-name is visible as if it were declared in the nearest enclosing namespace which contains both the using-directive and namespace-name.仅在命名空间 scope 和块 scope 中允许使用指令。从使用指令之后的任何名称的非限定名称查找的角度来看,直到它出现的 scope 结束,命名空间名称中的每个名称都是可见,就好像它是在最近的包含 using-directive 和 namespace-name 的封闭命名空间中声明的一样

Using-directive does not add any names to the declarative region in which it appears (unlike the using-declaration), and thus does not prevent identical names from being declared. using-directive 不会将任何名称添加到它出现的声明区域(与 using-declaration 不同),因此不会阻止声明相同的名称。

This means that a using directive does not introduce name in the declarative region (which is nothing but the main function in your example), but instead to the nearest enclosing namespace( which is the global namespace in your example).这意味着using directive不会在声明区域中引入名称(在您的示例中它只是main的 function),而是引入最近的封闭命名空间(在您的示例中是global namespace )。

Now, when unqualified lookup happens for the call expression equal(v, v);现在,当调用表达式equal(v, v);发生非限定查找时 the search goes upwards from the point where the call expression was encountered and it finds the equal version that was introduced due to the using declaration in the declarative region(which is main ) and hence the search stops.搜索从遇到调用表达式的点向上进行,并找到由于声明区域(即main )中的using declaration而引入的equal版本,因此搜索停止。 And so this already found version is used.所以这个已经找到的版本被使用。

A contrived example might help clarify the situation:一个人为的例子可能有助于澄清情况:

#include <iostream>
namespace X 
{
    void func(){std::cout<<"X version called"<<std::endl;}
}
namespace Y 
{
    void func(){std::cout<<"Y version called"<<std::endl;};
}
int main()
{
    using namespace X;
    using Y::func;
    
    func(); //calls Y version
    return 0;
}

Demo演示


Snippet 1片段 1

Snippet 1 in your example can also be understood based upon the quoted statement above.您的示例中的代码段 1 也可以根据上面引用的语句来理解。 In particular, you're getting ambiguous error in snippet 1 because both the namespaces ranges and boost::hana have a function called equal that are equally ranked.特别是,您在片段 1 中遇到了不明确的错误,因为命名空间rangesboost::hana都有一个 function 被称为equal ,它们的排名相同 So when the unqualified name lookup happens for the call expression equal(v,v) the search starts and goes upwards from the point where the call expression was encountered and finds functions named equal that were made visible in the global namescope due to both of the namespaces.因此,当调用表达式equal(v,v)发生非限定名称查找时,搜索开始并从遇到调用表达式的点向上查找,并找到名为equal的函数,由于这两个原因,它们在全局名称范围中可见名称空间。 Moreover, since both are equally ranked, we get the mentioned ambiguous error.此外,由于两者排名相同,我们得到了提到的模棱两可的错误。

A contrived example might help clarify the situation:一个人为的例子可能有助于澄清情况:

#include <iostream>
namespace X 
{
    void func(int)
    {
        std::cout<<"X version func called"<<std::endl;
    }
    
    void foo()
    {
        std::cout<<"X version foo called"<<std::endl;
    }
}
namespace Y 
{
    void func(double)
    {
        std::cout<<"Y version func called"<<std::endl;
    }
    void foo()
    {
        std::cout<<"Y version foo called"<<std::endl;
    }
}
int main()
{
    using namespace X ;
    using namespace Y;
    
    func(3); //calls X's func 
    func(5.5);//calls Y's func
    
    foo();//fails due to ambiguity
    return 0;
}

Demo演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM