请考虑以下代码:
struct base {};
struct derived : public base {
using base::base;
base foo() const; // how does name lookup on 'base' here work?
};
直观地说,很明显这段代码是有效的,并且它确实编译(用gcc和clang测试)。
但是,我想了解标准中的内容是否有效。具体来说,我想了解base
中base foo()
的名称查找如何找到基类类型而不是继承的构造函数。
这是我对标准措辞的分析,表明它应该解决给构造函数。这可能是错的,但我想知道我哪里出错了。
我从[class.member.lookup] p1
开始:
成员名称查找确定类范围中名称( id-expression )的含义。 [...]对于 id-expression ,名称查找从
this
的类范围开始
p7
告诉我们名称查找的结果是什么:
[类范围]
f
中[成员名称]C
的名称查找结果是 S(f,C)的声明集
我尝试按C
derived
f
base
和base foo()
使用p3
来执行此程序。
"宣言集"在f
:
C
中f
的查找集,名为 S(f,C),由两个组件集组成:声明集,一组名为p4
的成员; [...]
C
告诉我们声明集的内容:
如果
f
包含名称f
的声明,则声明集包含C
中声明的using base::base
声明,满足语言结构的要求。查找发生。
base
是f
(derived
)中名称C
(using base::base
)的声明。该段继续举例说明声明不对于满足查找发生的语言结构要求的含义,但没有任何内容可以排除{{1从这次查找。
接下来,在p3
向下,我们会告诉我们如何处理声明集中的 using-declarations :
在声明集中, using-declarations 被替换为未被派生类成员隐藏或覆盖的指定成员集
那么成员using base::base
指定的是什么?在[class.qual] p2
:
在查找中,不忽略函数名称和 nested-name-specifier 指定一个类
C
:
如果在
C
中查找 nested-name-specifier 之后指定的名称,则为C
的注入类名称,或者- 的最后一个组件中的标识符 [...]
在 using-declaration member-declaration 中,如果在 nested-name-specifier 之后指定的名称是相同的 嵌套名称说明符
而是将名称视为命名类
C
的构造函数。
有一个脚注,阐明了哪些"查找哪些函数名称不被忽略"的意思是:
忽略函数名称的查找包括出现在嵌套名称说明符中的名称, elaborated-type-specifier 或 base-specifier
这些名称查找的情况都不是这样,所以在我看来这个段落适用,并说using base::base
指定构造函数(这也是你直觉所期望的,鉴于它是继承构造函数声明。)
在派生类范围内找到声明(指定基类构造函数)之后,我们继续关注[class.member.lookup] p4
:
如果结果声明集不为空,则子对象集本身包含
C
,计算完成。
也就是说,由于名称查找在派生类范围内找到了结果,因此它不会继续查找基类范围(它会找到 inject-class-name {{1 }})。 [顺便说一句,即使名称查找继续进入基类范围,我也看不到任何会在构造函数和注入类名称之间消除歧义的东西。
我的推理在哪里出错?
答案 0 :(得分:4)
标准痛苦地指出构造函数没有名称。名称查找无法找到它,因为它没有名称。
C ++11§12.1/ 1C +11§12.1/ 2“构造函数没有名称。
“因为构造函数没有名称,所以它们是 在名字查找期间从未找到过。