这是一个学术问题。
在GCC bug 38764的报告中,有以下示例:
template < class T > struct A {};
typedef A< float > A; // Accepted by Comeau, but not GCC
typedef ::A< float > A; // Accepted by GCC but not Comeau
我知道为什么代码可能无效,但我的其中一条评论有问题:
此代码无效,但标准说明在这种情况下不需要诊断,因此两个编译器都符合标准。
为什么标准接受的“无效”代码有效?标准对此案例的具体说明是什么(模板+具有相同名称的类型),并且通常涉及各种实体(类型,模板,函数,变量)的名称空间?
答案 0 :(得分:11)
当标准说“不需要诊断”时,这意味着编译器不必产生关于无效代码的错误或警告,但是代码的行为仍然根据标准未定义,因此它不会必然有可预测的结果。这是为了使编译器编写器更容易,这样他们就没有义务检测相对稀少或特别麻烦的检测程序员错误。
但是,当违反“无需诊断”的规则时,编译器不会禁止检测到无效代码,并且出于对用户的礼貌而产生错误。因此,在给出的示例中,gcc正在为一种特定类型的无效代码生成礼貌诊断,并且Comeau正在为类似的无效代码生成礼貌诊断。但是不需要诊断,因此在任何情况下,其他编译器都不会产生错误消息而违反标准。在任何情况下,代码的行为都是未定义的。
关于类名和模板名的几个相关标准引用:
3.4 / 1
名称查找规则统一适用 所有名称(包括typedef-names (7.1.3),命名空间名称(7.3)和 类别(9.1))无论在哪里 语法允许这样的名字 上下文讨论了一个特定的 规则。名称查找关联使用 具有声明(3.1)的名称 那个名字。名称查找应找到 明确的名称声明 (见10.2)。 [...]
7.1.3 / 3
在给定范围内,是typedef说明符 不得用于重新定义名称 在该范围内声明的任何类型的 指的是另一种类型。 [实施例:
class complex { /* ... */ };
typedef int complex; // error: redefinition
-end example]同样,在给定的 范围,类别或枚举 不得与...同名 一个在其中声明的typedef-name 该范围并指其他类型 比类或枚举本身。 [...]
9.1 / 2
类定义介绍了 类名称放在它所在的范围内 定义并隐藏任何类,对象, 功能或其他声明 封闭范围内的名称(3.3)。如果一个 类名在范围内声明 对象,功能或者 同名的调查员也是 声明,然后当两个声明 在范围内,班级可以 仅提到使用 elaborated-type-specifier(3.4.4)。
14/5
一个类模板不应该有 与任何其他模板同名, 类,函数,对象,枚举, 枚举器,命名空间或类型 相同范围(3.3),除非另有说明 在(14.5.4)。除了一个功能 模板可以重载 (非模板)功能相同 名称或其他功能模板 同名(14.8.3),a 在命名空间中声明的模板名 范围或类别范围 在该范围内是独一无二的。
14.5.4 / 1
主类模板声明 是一个类模板 name是一个标识符。一个模板 声明在哪个班级 模板名称是模板ID,是一个 课程的部分专业化 模板id中指定的模板。一个 一个类的部分特化 模板提供了另一种选择 模板的定义是 用来代替主要定义 什么时候专业化的论点 匹配部分给出的那些 专业化(14.5.4.1)。 [...]
所以,总结一下:
typedef
s无法更改现有类型的含义class
名称可能与某些名称冲突,但不会与其他类名冲突template
类名不包含模板参数,并且不能与任何内容冲突,即使正常类名允许与之冲突的内容所以这里两个方向都存在冲突。 template
名称不允许与任何内容冲突,并且typedef
不允许将A
从模板类类型更改为模板类类型的特化。
答案 1 :(得分:4)
为什么标准接受的“无效”代码有效?
不是。如果代码无效,则无效。
应用于语法或语义规则时,短语无需诊断意味着如果您的程序违反规则,编译器不必发出错误消息,并且可以继续编译程序(或者它可以做任何其他事情,真的;如果你给它一个违反这个规则的程序,标准对编译器没有任何要求。)
从某种意义上说,不需要诊断有点像语义规则的未定义行为:如果你违反了不需要诊断的规则,所有的赌注都是关闭。