【问题标题】:Name hiding by using declaration使用声明隐藏名称
【发布时间】:2016-03-09 14:54:08
【问题描述】:
#include <iostream>

struct H
{
    void swap(H &rhs); 
};    

void swap(H &, H &)
{
    std::cout << "swap(H &t1, H &t2)" << std::endl;
}

void H::swap(H &rhs)
{
    using std::swap;
    swap(*this, rhs);
}


int main(void)
{
    H a;
    H b;

    a.swap(b);
}

结果如下:

swap(H &t1, H &t2)

在上面的代码中,我尝试定义一个交换函数H。在函数void H::swap(H &amp;rhs) 中,我使用 using 声明使名称 std::swap 可见。如果没有 using 声明,则无法编译代码,因为在类 H 中没有具有两个参数的可用交换函数。

我有一个问题。在我看来,在我使用了 using 声明 -- using std::swap 之后,它只是让 std::swap -- STL 中的模板函数可见。所以我认为应该在H::swap() 中调用STL 中的交换。但结果显示,void swap(H &amp;t1, H &amp;t2) 被调用了。

所以这是我的问题:

  1. 为什么我不能在没有 using 声明的情况下调用 swap?(我猜是因为类中没有带两个参数的 swap 函数。但我不确定。)
  2. 为什么会调用我定义的交换而不是 H::swap 中的 STL 交换?

【问题讨论】:

  • 您在问题中留下了很多不相关(分散注意力)的代码。请提供minimal reproducible example
  • 我会写一个答案,但我不确定参数相关查找的技术细节。不过,这应该是一个非常容易搜索的术语。 (您的怀疑 1 是正确的;当在类中找到名称时,重载解析不会冒险到类之外。)
  • @WingCuengRay 我删除了所有这些代码是有原因的——它与这个问题完全无关,也让人分心。您不需要任何构造函数或运算符来演示您遇到的问题。

标签: c++ swap using argument-dependent-lookup name-lookup


【解决方案1】:
  1. 为什么我不能在没有 using 声明的情况下调用 swap?

我们从最近的封闭范围开始,然后向外工作,直到找到一些东西。有了这个:

void H::swap(H &rhs)
{
    swap(*this, rhs);
}

不合格的swap 会找到H::swap()。然后我们进行参数相关的查找。但是有规则,来自[basic.lookup.argdep]:

X 为由非限定查找 (3.4.1) 生成的查找集,让 Y 为由 参数相关查找(定义如下)。如果 X 包含
— 类成员的声明,或
— 不是 using-declaration 的块范围函数声明,或
— 既不是函数也不是函数模板的声明
那么 Y 为空。否则,Y 是在与参数类型相关的命名空间中找到的一组声明,如下所述。 [...]

由于非限定查找集找到了类成员,所以依赖参数的查找集为空(即没有找到swap(H&amp;, H&amp;))。

  1. 为什么会调用我定义的交换而不是 H::swap 中的 STL 交换?

添加时:

void H::swap(H &rhs)
{
    using std::swap;
    swap(*this, rhs);
}

现在不合格的 swap 会找到 std::swap()not H::swap(),因为前者是在更内部的范围内声明的。 using std::swap; 不符合上述规则中的任何条件,这些条件会导致 Y 为空(它不是类成员,它 is 是一个 using-declaration,它是一个函数模板)。因此,依赖于参数的查找集确实包含在关联命名空间中找到的声明 - 其中包括 swap(H&amp;, H&amp;)(因为 H 在全局命名空间中)。我们最终得到了两个重载候选者——你的候选者是首选,因为它是非模板。


请参阅Xeo's answer,了解将交换添加到您的课程的首选方式。基本上,你想写:

struct H {
    friend void swap(H&, H&) { ... }
};

这将由 ADL(并且仅由 ADL)找到。然后每当有人调用交换正确:

using std::swap;
swap(a, b);

Lookup 会在适当的地方找到您的。

【讨论】:

  • “然后我们进行参数相关查找”...“我们不进行参数相关查找”令人困惑的答案!
  • 你的意思是 [basic.lookup.argdep] 的规则不适用,因为不合格的交换只在内部范围内找到std::swap 而不是H::swap,所以两者都是由于 ADL,找到了候选人并应用了最佳匹配?但是,void swap(H &amp;, H &amp;) 是在全局范围而不是命名空间中定义的。没有命名空间似乎不适合 ADL。
  • @WingCuengRay ADL 在参数类型的关联命名空间中查找。在这种情况下,关联的命名空间是全局命名空间。 ADL 仅与查找有关 - 重载解决方案是一个单独的过程。
  • 对了,“Let X ...”这句话出自哪本书?
  • @WingCuengRay C++ 标准,最新工作草案。我添加了一个不错的在线可链接版本的链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-12
相关资源
最近更新 更多