代码:
#include <iostream>
namespace A
{
class D{ };
class C
{
public:
static const int a=7;
~C(){ std::cout << "Destroyed"; }
C() { std::cout << "Created"; }
};
}
int main()
{
typedef A::C zlp;
zlp *z= new zlp();
z->A::D::~zlp();//error: ‘A::D’ is not a base of ‘zlp {aka A::C}’
}
我读了3.4.3/1 N3797。有写的
如果一个伪析构函数名(5.2.4)包含一个嵌套名称说明符,则类型名将作为嵌套名称说明符指定的作用域中的类型进行查找。类似地,在以下形式的限定id中:
nested-name-specifier_opt class-name :: ~ class-name
第二个类名在与第一个类名相同的作用域中查找。
这句话并不是说nested-name-specifier_opt class-name
必须是zlp
的基类型。你能解释这种行为吗?我想找一个相应的参考标准。
1条答案
按热度按时间ryevplcw1#
编译器可以尝试分析构造
作为“postfix-expression
->
template
optid-expression”(普通成员访问表达式)或作为“postfix-expression->
pseudo-destructor-name”(参见N3797的[expr.post]/1中的语法)。[expr.pseudo]/1,在伪析构函数调用中,只允许左操作数为标量类型。显然,
z->A::D::~zlp()
不是有效的伪析构函数调用。该标准的意图是,当左操作数是类类型时,第一个语法产生式是适用的(因为第二个需要标量类型,显然是病态的)。语法歧义在C++20中被删除。这和这个问题没有直接关系,所以我不想进一步讨论。
回到N3797,问题是我们是否可以将
z->A::D::~zlp
解释为形式为“postfix-expression->
template
optid-expression”的有效成员访问表达式。它实际上归结为A::D::~zlp
是否是有效的 id-expression。[expr.prim.general]管理 id-expressions,第9段特别关注 qualified-ids,其中 nested-name-specifier 命名一个类:一个 nested-name-specifier 表示一个类,可选地后跟关键字
template
(14.2),然后后跟该类(9.2)或其基类之一(第10章)的成员的名称,是一个 qualified-id;3.4.3.1描述了对出现在 qualified-ids 中的类成员的名称查找。结果是成员。结果的类型就是成员的类型。如果成员是静态成员函数或数据成员,则结果为左值,否则为纯右值。[* 注:*...]如果使用 class-name::
~
class-name,则两个class-name指的是同一个类;这个符号命名了析构函数(12.4)。[...]因为
~zlp
既不是A::D
的成员,也不是A::D
的基类的成员(实际上,A::D
没有基类),所以A::D::~zlp
甚至不是有效的 qualified-id。即使它是一个 qualified-id,它仍然是病态的,因为命名析构函数的特殊规则,其中类型必须完全匹配;你不能用 nested-name-specifier 来命名基类析构函数,表示派生类。