我相信[namespace.memdef]/1的新措辞试图解释命名空间X
中的两个声明using M::g;
和void g();
之间的冲突,但我无法理解这个新措辞和所提到的冲突之间的关系。
命名空间N
中的声明(不包括嵌套作用域中的声明),其 declarator-id 为 unqualified-id([dcl.meaning]),whose class-head-name(子句[类])或 enum-head-name([dcl.enum])是一个 identifier,或者其 elaborated-type-specifier 的格式为 class-keyattribute-specifier-seqoptidentifier([dcl.type.elab])或 * opaque-enum-declaration*,声明(或重新声明)其 unqualified-id 或 identifier 为N
的成员。[注意:模板的显式示例化([temp.explicit])或显式专门化([temp.expl.spec])不引入名称,因此如果主模板在内联名称空间中声明,则可以在封闭名称空间集合的成员中使用 unqualified-id 进行声明。
namespace X {
void f() { /* ... */ } // OK: introduces X::f()
namespace M {
void g(); // OK: introduces X::M::g()
}
using M::g;
void g(); // error: conflicts with X::M::g()
}
- 结束示例]
即使当我看到DR 1838(可能是这一段变化的起源)时,我也无法理解以下句子(重点是我的):
当一个实体在内部命名空间中声明但没有定义,而是通过外部命名空间中的 using-declaration 声明时,该标准并不清楚会发生什么,并且具有该名称的实体的definition作为 unqualified-id 出现在外部命名空间中。这是内部命名空间实体的合法定义吗?如果定义使用 qualified-id,或者该定义是外部命名空间的成员,因此与 using-declaration 冲突?在处理此类定义方面存在实现分歧。
这句话后面的例子与[namespace.memdef]/1
段落中的例子完全相同。我突出显示了上面的单词definition,因为在提到的例子中没有函数X::g()
的定义。我错过了什么?
1条答案
按热度按时间yhxst69z1#
引用的段落表明,由于外部
void g();
使用 unqualified-id 作为其 declarator-id,因此它将g
声明为外部命名空间的成员,即X
。C17 [namespace.udecl]/14也声明如下:
如果命名空间作用域或块作用域中的函数声明与 using-declaration 引入的函数具有相同的名称和相同的parameter-type-list(11.3.5),并且声明不声明相同的函数,则程序是病态的。
问题1838解决方案背后的思想是,你现在有一个
g
的声明,作为X
的成员,但是也有一个由using-declaration引入的g
,它是X::M
的成员,它们有相同的名字和相同的参数类型列表,但是它们不是相同的函数,所以违反了这个规则,并且程序是病态的。我不确定即使在这个变化之后,措辞是否完全清楚;我们怎么知道这两个
g
真的不是同一个函数呢?根据C17 [basic.link]/9,相同(第6条)且在不同作用域中声明的两个名称应表示相同的变量、函数、类型、模板或命名空间,如果
有人可能会说,由于
X::M::g
也是通过 using-declaration 带入X
的,因此它也是X
的成员。意味着在它和另一个X::g
之间满足所有4个标准。(文本并没有明确说明 using-declaration 是否声明某个东西是它出现的名称空间的成员。因此,我认为这个问题当时并没有完全解决。然而,在C++23草案中,它确实得到了解决。参见N4928 [basic.scope.scope]/2.4,[basic.scope.scope]/5,[basic.link]/8,[namespace.udecl]/10。