Pas*_* By 5 c++ language-lawyer c++14
是否有关于如何解决歧义语法的一般规则?
特别是,伪析构函数名称包括这些产生规则
嵌套名称说明符opt类型名称 :: ~ 类型名称
嵌套名称说明符opt ~ 类型名称
嵌套名称说明符包括
嵌套名称说明符标识符 ::
类型名称 ::
鉴于以下情况
struct A
{
struct B {};
B b;
};
A a;
a.b.A::B::~B();
Run Code Online (Sandbox Code Playgroud)
最后一条生产线选择以下哪一种产品?
类型名称 :: 类型名称 :: ~ 类型名称
类型名称 :: 标识符 :: ~ 类型名称
这在模板化上下文中具有重要意义,因为[temp.res]
在立即包含依赖于模板参数的嵌套名称说明符的嵌套名称说明符中,隐式假定标识符或 simple-template-id 来命名类型,而不使用 typename 关键字。
当出现语法歧义时,应附有消歧规则。一些这样的规则是相当具体的(例如[expr.unary.op]/10),而其他规则则相当笼统(例如[dcl.abig.res]/1)。如果没有适用于给定歧义的消歧规则,则该歧义代表标准中的意外缺陷。不存在足够通用的消歧规则来解决所有可能的歧义。
\n在C++14语法中,有一个你没有提到的歧义(由@xskxzr指出);它介于
\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0后缀表达式 . templateopt id 表达式
和
\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0后缀表达式 . 伪析构函数名称
(参见[expr.post]/1)。
\n由于A::B它实际上是一个类类型,因此大概是为了有利于前者而解决这种歧义。事实上,如果它被解释为伪析构函数名称,那么在 [expr.pseudo]/2 下它将是错误的。它被称为伪析构函数调用的原因是它对标量类型进行操作,标量类型没有实际的析构函数:
\n\n点运算符的左侧应为标量类型。[..] 该标量类型是对象类型。对象类型和伪析构函数名称指定的类型的 cv 未限定版本应为同一类型。[...]
\n
似乎没有适用的消歧规则,因此这可以被视为缺陷。然而,在 C++20 中,语法无论如何都发生了变化,所以它没有实际意义。我将在稍后的答案中详细讨论这一点。
\n假设我们更改您的示例,使其涉及标量类型:
\nstruct A\n{\n using C = int;\n C c;\n};\n\nA a;\na.c.A::C::~C();\nRun Code Online (Sandbox Code Playgroud)\n现在,A::C::~C不能是id-expression,因为如果它是id-expression,则它必须是由嵌套名称说明符和非限定 id组成的限定 id ([expr.prim.general]/9) ,并且如果是类名或decltype 说明符([expr.prim.general]/1),则只能是非限定 ID ,但不是类名,因为它尚未声明为类 ( [类]/1)。所以只能是伪析构函数名称,而不是id-表达式。 A::C:: ~C~CCCA::C::~C
所以现在的问题变成了如何解释A::C::~C为伪析构函数名称。这说明了您想要说明的歧义。
CWG 1753的提交者似乎认为嵌套名称说明符 ~ 类型名称形式仅旨在涵盖嵌套名称说明符指定命名空间(而不是类)的情况。问题页面显示该问题被投票为 DR。这意味着其删除嵌套名称说明符 ~ 类型名称生成\xe2\x80\x94 的解决方案\xe2\x80\x94 具有追溯力。换句话说,委员会正式消除了这种歧义,不是通过插入歧义解决规则,而是通过说嵌套名称说明符 ~ 类型名称解释从一开始就不应该是合法的。
所以正确的解释是nested-name-specifier type-name :: ~ type-name。
在 C++20 中,伪析构函数名称的概念被完全废除。这意味着@xskxzr 提到的歧义也得到了修复。在 C++20 中,曾经的伪析构函数名称现在只是一种特殊类型的id 表达式,当它表示的析构函数是假析构函数(即非类类型之一)时,就会出现这种情况。(出于好奇,这个更改是由P1131R2进行的。)
\n| 归档时间: |
|
| 查看次数: |
196 次 |
| 最近记录: |