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

Sea*_*ean 14 c++ scope namespaces

我的困惑来自"C++ Primer 5th edition"第13.3节,第518页.

非常仔细的读者可能想知道为什么using里面的声明swap不会隐藏HasPtr版本的声明swap.

我试图阅读它的参考但仍然不明白为什么.有人可以解释一下吗?谢谢.这是问题的代码示例.

假设类Foo有一个名为的成员h,它具有类型HasPtr.

void swap(HasPtr &lhs, HasPtr &rhs)
{...}

void swap(Foo &lhs, Foo &rhs)
{
    using std::swap;
    swap(lhs.h, rhs.h);
}
Run Code Online (Sandbox Code Playgroud)

为什么swap对于HasPtr没有隐藏这似乎在外部范围中声明,而using std::swap在内部范围?谢谢.

mol*_*ilo 10

由于using std::swap;并不意味着"从今以后,每一个'交换’应该用std::swap",而是"带来的所有重载swapstd到目前的范围".

在这种情况下,效果与您using namespace std;在函数内部编写的效果相同.


R S*_*ahu 7

using声明 using std::swap并不能掩盖你声明交换的功能HasPtrFoo.它带来的名字swap形成了std命名空间声明区.有了它,std::swap可以参与重载决议.

从C++ 11标准:

7.3.3使用声明

1 using声明在声明区域中引入了一个名称,其中出现了using声明.

using声明:

using typenameopt nested-name-specifier unqualified-id;
using :: 不合格的;

using声明中指定的成员名称在using声明出现的声明区域中声明.[ 注意:只声明指定的名称; 在using-declaration中指定枚举名称不会在using-declaration的声明性区域中声明其枚举数.-end note ]如果using声明命名一个构造函数(3.4.3.1),它会隐式声明出现using-declaration的类中的一组构造函数(12.9); 否则,using-declaration中指定的名称是在其他地方声明的某个实体的名称的同义词.

在您的情况下,您有:

void swap(Foo &lhs, Foo &rhs)
{
    using std::swap;
    swap(lhs.h, rhs.h);
}
Run Code Online (Sandbox Code Playgroud)

using std::swap;声明引入的名字swapstd命名空间到声明性区域,这是身体swap(Foo&, Foo&)功能.这个名字swap来自全局命名空间仍然是在函数体访问.

如果您发布的是整个函数,那么您不需要using std::swap声明.你可以通过以下方式得到:

void swap(Foo &lhs, Foo &rhs)
{
    swap(lhs.h, rhs.h);
}
Run Code Online (Sandbox Code Playgroud)

因为swap(HasPtr &lhs, HasPtr &rhs)从功能可见.

现在,看看下面的例子.

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);
}
Run Code Online (Sandbox Code Playgroud)

标记的行A problem是一个问题,因为没有名为的函数swap可以使用两个类型的对象int&作为参数.您可以使用以下方法之一解决此问题:

  1. std::swap明确使用.

    void swap(Foo& lhs, Foo& rhs)
    {
       std::swap(lhs.a, rhs.a);
       swap(lhs.b, rhs.b);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 介绍std::swap这个功能.

    void swap(Foo& lhs, Foo& rhs)
    {
       using std::swap;
       swap(lhs.a, rhs.a);
       swap(lhs.b, rhs.b);
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • "使用声明不会隐藏任何内容" - 它确实隐藏了在全局命名空间中声明的`swap`,以便在这种情况下进行简单的非限定查找.但是,ADL仍然可以找到`swap`,因为`HasPtr`的关联命名空间是全局命名空间.如果全局`swap`有参数,比如说,`int&`并且你用`int`类型的参数调用它(它没有关联的命名空间,所以ADL没有找到任何东西),你会看到隐藏引入的using声明(即使全局重载更好匹配,也会调用`std`重载). (3认同)