在 C++ 中有两种类型的名称隐藏:
1)普通名称隐藏:[basic.scope.hiding]p1(http://eel.is/c++draft/basic.scope.hiding#1):
可以通过在嵌套声明区域或派生类 ([class.member.lookup]) 中显式声明相同名称来隐藏名称。
2) [basic.scope.hiding]p2 ( http://eel.is/c++draft/basic.scope.hiding#2 ) 中隐藏的特殊名称类型:
类名 ([class.name]) 或枚举名 ([dcl.enum]) 可以被同一作用域中声明的变量、数据成员、函数或枚举器的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器在同一范围内(以任何顺序)以相同名称声明,则无论变量、数据成员、函数或枚举器名称可见。
我很想知道在执行非限定名称查找时名称隐藏如何与 using-directives 交互。
对于第一种类型的名称隐藏行为是非常清楚的。这是因为 [basic.scope.hiding]p1 已根据 [basic.lookup.unqual] ( http://eel.is/c++draft/basic.lookup.unqual )部分中的规则重新制定
第二种类型的名称隐藏没有这样做。所以现在出现了以下问题:
*) 这第二种类型的名称隐藏应该如何与涉及使用指令的非限定名称查找交互?
在标准的其他地方我发现 [namespace.udir]p2 ( http://eel.is/c++draft/namespace.udir#2 ) 我认为这是回答这个问题的关键:
using-directive 指定指定命名空间中的名称可以在 using-directive 出现在 using-directive 之后的范围内使用。在非限定名称查找 ([basic.lookup.unqual]) 期间,名称看起来好像它们是在 最近的封闭命名空间中声明的,其中包含使用指令和指定命名空间。[注:在此上下文中,“包含”是指“直接或间接包含”。——尾注]
将此规则的 asif 部分应用于[ basic.scope.hiding ]p1 与 [basic.lookup.unqual] 部分中的规则保持一致。此应用程序也与 [basic.scope.hiding]p4 ( http://eel.is/c++draft/basic.scope.hiding#4 ) 一致,因此看起来很有希望。
因此,我认为我们可以通过类似地将 [namespace.udir]p2 的as if部分应用于 [basic.scope.hiding]p2 来回答问题 *)。此应用程序也与 [basic.scope.hiding] p4 一致。我认为这也是对 c++ 标准最自然、最简单的解释。
然而问题是 Clang 和 GCC 并没有做出与我相同的解释。例如:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
根据我的解释,这个程序应该是格式正确的,i
应该作为整数变量来查找。Clang 和 GCC 都不同意这一点,因为它给出了名称查找歧义。
在 Clang 的情况下,这种更复杂的解释会导致以下错误:
namespace N { static int i = 1; }
namespace M { struct i {}; }
namespace P {
using N::i;
using M::i;
}
namespace Q { using M::i; }
using namespace P;
using namespace Q;
int main() { sizeof (i); }
没有错误,但改变
using namespace P;
using namespace Q;
进入
using namespace Q;
using namespace P;
我们得到名称查找歧义错误。GCC 至少在这里是一致的。
我是否正确解释了 C++ 标准?