C++ 在C+中隐藏和使用函数声明+;
我的困惑来自于“C++入门第五版”第13.3节,第518页 非常仔细的读者可能会想,为什么C++ 在C+中隐藏和使用函数声明+;,c++,scope,namespaces,C++,Scope,Namespaces,我的困惑来自于“C++入门第五版”第13.3节,第518页 非常仔细的读者可能会想,为什么在交换中使用声明不会隐藏HasPtr版本的交换的声明 我试图阅读它的参考资料,但仍然不明白为什么。谁能解释一下吗?谢谢下面是问题的代码示例 假设类Foo有一个名为h的成员,其类型为HasPtr void swap(HasPtr &lhs, HasPtr &rhs) {...} void swap(Foo &lhs, Foo &rhs) { using std::sw
在交换
中使用声明不会隐藏HasPtr
版本的交换
的声明
我试图阅读它的参考资料,但仍然不明白为什么。谁能解释一下吗?谢谢下面是问题的代码示例
假设类Foo
有一个名为h
的成员,其类型为HasPtr
void swap(HasPtr &lhs, HasPtr &rhs)
{...}
void swap(Foo &lhs, Foo &rhs)
{
using std::swap;
swap(lhs.h, rhs.h);
}
为什么swap
forHasPtr
没有隐藏,而使用std::swap
在内部作用域中,它似乎在外部作用域中声明?谢谢。因为使用std::swap
并不意味着“从此以后,每个‘交换’都应该使用std::swap
”,而是“将swap
的所有重载从std
带入当前范围”
在本例中,效果与使用名称空间std编写的相同代码>函数内.< /P> < P> Scott Meyers的有效C++第三版(项目24)< /P>
void swap(Foo& lhs, Foo& rhs)
{
using std::swap;
swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
当编译器看到对swap的调用时,他们会搜索对swap的正确调用
援引C++的名称查找规则确保这将找到任何
在全局范围内或与类型位于同一命名空间中的特定于T的交换
T
在这种情况下,在第二个代码块中,编译器寻找一个HASPTR交换,如果他们找不到,它们会回到STD中的一般版本 < P>使用声明意味着考虑所有的STD::SWAP重载,就像它们被定义在与函数相同的命名空间中一样。由于using声明出现在函数体中,因此这只会暂时起作用:在该范围内
它实际上与以下内容相同:
void swap(HasPtr &lhs, HasPtr &rhs)
{...}
void swap(int &lhs, int &rhs) { std::swap(lhs, rhs); }
void swap(char &lhs, char &rhs) { std::swap(lhs, rhs); }
// etc. for other std::swap overloads of common types
void swap(Foo &lhs, Foo &rhs)
{
swap(lhs.h, rhs.h);
// the other overloads of swap go out of scope here.
}
重载的常规规则确保第一次交换是被调用的交换。这与声明名为“swap”的局部变量形成对比,后者将隐藏第一个重载。使用声明using std::swap
不会隐藏您声明要交换的函数HasPtr
和Foo
。它将名称swap
从std
命名空间带到声明区域。这样,std::swap
就可以参与重载解析
从C++11标准:
7.3.3使用声明
1 using声明在using声明出现的声明性区域中引入名称
使用声明:
使用typename
选择嵌套名称说明符非限定id
使用::
非限定id
using声明中指定的成员名称在using声明出现的声明性区域中声明。[注意:只声明指定的名称;在using声明中指定枚举名称不会在using声明的声明区域中声明其枚举数。-结束注意]如果using声明命名构造函数(3.4.3.1),则它会在using声明出现的类中隐式声明一组构造函数(12.9);否则,使用声明中指定的名称是其他地方声明的某实体名称的同义词
就您而言,您有:
void swap(Foo &lhs, Foo &rhs)
{
using std::swap;
swap(lhs.h, rhs.h);
}
using std::swap;
声明将std
命名空间中的名称swap
引入声明性区域,该区域是swap(Foo&,Foo&)
函数的主体。全局命名空间中的名称swap
仍然可以在函数主体中访问
void swap(Foo& lhs, Foo& rhs)
{
using std::swap;
swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
如果您发布的是整个函数,那么您不需要使用std::swap的声明。您只需要:
void swap(Foo &lhs, Foo &rhs)
{
swap(lhs.h, rhs.h);
}
因为交换(HasPtr&lhs,HasPtr&rhs)
从函数中可见
void swap(Foo& lhs, Foo& rhs)
{
using std::swap;
swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
现在,看看下面的例子
struct Bar {};
void swap(Bar& lhs, Bar& rhs)
{
}
struct Foo
{
int a;
Bar b;
};
void swap(Foo& lhs, Foo& rhs)
{
swap(lhs.a, rhs.a); // A problem
swap(lhs.b, rhs.b);
}
标记为A problem
的行是一个问题,因为没有名为swap
的函数可以使用两个int&
类型的对象作为参数。您可以使用以下方法之一修复此问题:
明确使用std::swap
void swap(Foo& lhs, Foo& rhs)
{
std::swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
在函数中引入std::swap
void swap(Foo& lhs, Foo& rhs)
{
using std::swap;
swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
实际上,HasPtr的swap
在内部作用域中使用std::swap
时是隐藏的,但是在这种情况下,内部作用域中的std::swap
与外部作用域中的HasPtr的swap
是相同的。因为使用对我理解使用声明没有影响在std
中使用swap
,但是如果它的工作方式类似于正常的函数声明,它应该在外层空间隐藏名称,而不仅仅是在std
中引入名称。顺便说一句,使用的声明和指令是不同的,这让我感到困惑。谢谢。而且声明和指令是不同的但正如我所写的,在这种情况下效果是一样的。谢谢。如果f
是变量,那么它应该被隐藏,对吗?变量和函数的声明有不同的隐藏策略?事实上,我刚刚尝试过,在你的例子中,外层空间中的f将被隐藏。@Sean是的,你是对的。对不起,我不应该这么做。“使用声明不会隐藏任何内容"-在本例中,它确实隐藏了全局命名空间中声明的swap
,以便进行简单的非限定查找。但是,ADL仍然可以找到swap
,因为HasPtr
的关联命名空间是全局命名空间。如果全局swap
具有参数,例如,int&
,并且您使用类型为int
的rguments(没有相关的名称空间,因此ADL找不到任何内容),您将看到using声明引入的隐藏(将调用std
重载,即使