我知道这会模棱两可
#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);
}
因为在boost::hana
和ranges
命名空间中都有equal
。
但是,我认为这也将是模棱两可的:
#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);
}
但根据GCC和Clang的说法,情况并非如此。
为什么?
片段 2
让我们看看示例中的第二个代码段是如何工作的,因为您已经知道第一个代码段产生不明确错误的原因。
从使用指令的文档:
仅在命名空间范围和块范围内允许使用 using 指令。从 using-指令之后的任何名称的非限定名称查找的角度来看,直到它出现的范围的末尾,命名空间名称中的每个名称都是可见的,就好像它是在最近的封闭命名空间中声明的,该命名空间同时包含 using 指令和命名空间名称。
using-指令不会向它所在的声明性区域添加任何名称(与 using-声明不同),因此不会阻止声明相同的名称。
这意味着using directive
不会在声明性区域中引入 name(在示例中只不过是main
函数),而是引入最近的封闭命名空间(这是示例中的global namespace
)。
现在,当调用表达式发生非限定查找时equal(v, v);
搜索从遇到调用表达式的点向上,并找到由于声明性区域中using declaration
而引入的equal
版本(即main
),因此搜索停止。因此,使用了这个已经找到的版本。
一个人为的例子可能有助于澄清情况:
#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;
}
演示
<小时 />片段 1
示例中的代码段 1 也可以根据上面引用的语句来理解。特别是,代码段 1 中出现不明确的错误,因为命名空间ranges
和boost::hana
都有一个名为equal
的函数,这些函数排名相同。因此,当调用表达式equal(v,v)
非限定名称查找发生时,搜索将从遇到调用表达式的位置开始并向上,并查找名为equal
的函数,这些函数由于两个命名空间而在全局名称范围内可见。此外,由于两者的排名相同,我们得到了提到的模棱两可的错误。
一个人为的例子可能有助于澄清情况:
#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;
}
演示