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

时间:2017-02-22 10:05:47

标签: c++ scope namespaces

我的困惑来自" C ++ Primer第5版"第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);
}

为什么swap HasPtr未被隐藏,而using std::swap位于内部范围内似乎是在外部范围内声明的?感谢。

5 个答案:

答案 0 :(得分:10)

因为using std::swap;并不意味着“从此以后,每个'交换'应该使用std::swap”,但“将swap的所有重载从std带入当前范围” 。

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

答案 1 :(得分:6)

using-declaration using std::swap不会隐藏您声明为交换HasPtrFoo的函数。它将名称swapstd命名空间带到声明性区域。有了这个,std::swap可以参与重载决策。

来自C ++ 11标准:

  

7.3.3使用声明

     

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

     

using-declaration:

     

using typename opt nested-name-specifier unqualified-id;
     using :: unqualified-id;

     

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

在您的情况下,您有:

void swap(Foo &lhs, Foo &rhs)
{
    using std::swap;
    swap(lhs.h, rhs.h);
}

using std::swap;声明将swap命名空间中的名称std引入声明性区域,该区域是swap(Foo&, Foo&)函数的主体。全局命名空间中的名称swap仍可在函数体中访问。

如果你发布的是整个功能,那么你就不需要using std::swap声明。你可以只用:

void swap(Foo &lhs, Foo &rhs)
{
    swap(lhs.h, rhs.h);
}

因为函数可以看到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);
}

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

  1. 明确使用std::swap

    void swap(Foo& lhs, Foo& rhs)
    {
       std::swap(lhs.a, rhs.a);
       swap(lhs.b, rhs.b);
    }
    
  2. 在函数中引入std::swap

    void swap(Foo& lhs, Foo& rhs)
    {
       using std::swap;
       swap(lhs.a, rhs.a);
       swap(lhs.b, rhs.b);
    }
    

答案 2 :(得分:0)

Scott Meyers的有效C ++第三版(第24项)

  

当编译器看到对swap的调用时,他们会搜索正确的swap   调用。 C ++的名称查找规则确保这将找到任何   特定于T的交换在全局范围或与该类型相同的命名空间中   吨。

在这种情况下,在第二个代码块中,编译器会查找HasPtr交换,如果找不到它们,它们将回退到std中的通用版本。

答案 3 :(得分:0)

using声明意味着考虑所有std :: swap重载,就好像它们是在与函数相同的命名空间中定义的一样。由于using声明出现在函数体中,因此它只会暂时生效:在该范围内。

它与以下内容相同:

isPalindrome()

定期的重载规则确保第一个交换是被调用的交换。这与声明一个名为" swap"的局部变量形成对比,其中隐藏第一个重载。

答案 4 :(得分:0)

实际上,HasPtr的swap在内部范围内隐藏using std::swap,但在这种情况下,内部范围中的std::swapswap相同对于外部范围内的HasPtr。