【发布时间】:2016-04-12 19:54:13
【问题描述】:
考虑以下代码:
struct base {};
struct derived : public base {
using base::base;
base foo() const; // how does name lookup on 'base' here work?
};
直观地说,很明显这段代码是有效的,并且可以编译(用 gcc 和 clang 测试)。
但是,我想了解标准中的哪些内容使其有效。具体来说,我想了解base foo() 中base 的名称查找如何找到基类类型而不是继承的构造函数。
这是我对标准措辞的分析,表明它应该解析为构造函数。这可能是错误的,但我想知道我哪里出错了。
我从[class.member.lookup] p1开始:
成员名称查找确定名称(id-expression)在类范围内的含义。 [...] 对于 id-expression,名称查找从
this的类范围开始
p7 告诉我们名称查找的结果是什么:
[a member name]
fin [a class scope]C的名称查找结果是S(f, C)的声明集
我正在尝试遵循此程序,C 是 derived,f 是在 base foo() 中使用 base。
“声明集”定义在p3:
C中f的查找集,称为S(f, C),由两个组件集组成:声明集,一组名为f的成员; [...]
p4 告诉我们声明集中的内容:
如果
C包含名称为f的声明,则声明集包含C中声明的每个f声明,满足发生查找的语言构造的要求。
using base::base 是 derived (C) 中名称 base (f) 的声明。该段落继续举例说明声明 not 满足查找发生的语言结构的要求意味着什么,但没有任何内容可以将 using base::base 排除在此查找之外。
接下来,在p3 的下方,我们被告知如何处理声明集中的using-declarations:
在声明集中,using-declarations被派生类的成员不隐藏或覆盖的指定成员集替换
那么using base::base 指定了哪些成员?在我看来,[class.qual] p2 回答了这个问题:
在不忽略函数名的查找中, nested-name-specifier 指定一个类
C:
如果在 nested-name-specifier 之后指定的名称,当在
C中查找时,是C的注入类名称,或者- 的最后一个组件中
在 using-declaration 中,它是一个 member-declaration,如果在 nested-name-specifier 之后指定的名称是相同的 identifier [...] 在 nested-name-specifier
该名称被认为是命名类
C的构造函数。
有一个脚注阐明了“不忽略函数名称的查找”的含义:
忽略函数名称的查找包括出现在 nested-name-specifier、elaborated-type-specifier 或 base-specifier 中的名称.
这些都不是问题名称查找的情况,所以在我看来,这一段适用,并说using base::base 指定构造函数(这也是你直观地期望的,因为它是继承构造函数声明)。
在派生类范围内找到声明(指定基类构造函数)后,我们继续关注[class.member.lookup] p4:
如果结果声明集不为空,则子对象集包含
C本身,计算完成。
也就是说,由于名称查找在派生类范围内找到了结果,它不会继续在基类范围内查找(它会在其中找到 injected-class-name base )。 [顺便说一句,即使名称查找继续进入基类范围,我也看不到任何可以在构造函数和 injected-class-name 之间消除歧义的东西]。
我的推理哪里出错了?
【问题讨论】:
标签: c++ c++11 name-lookup inheriting-constructors injected-class-name