c++ 类类型的直接析构函数调用

htrmnn0y  于 2023-05-08  发布在  其他
关注(0)|答案(1)|浏览(194)

代码:

#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的基类型。你能解释这种行为吗?我想找一个相应的参考标准。

ryevplcw

ryevplcw1#

编译器可以尝试分析构造

z->A::D::~zlp

作为“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 来命名基类析构函数,表示派生类。

相关问题