Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C+中隐藏和使用函数声明+;_C++_Scope_Namespaces - Fatal编程技术网

C++ 在C+中隐藏和使用函数声明+;

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

我的困惑来自于“C++入门第五版”第13.3节,第518页

非常仔细的读者可能会想,为什么
交换
中使用
声明不会隐藏
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
for
HasPtr
没有隐藏,而
使用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
    重载,即使