在C ++中声明具有相同名称的类型和模板

时间:2010-07-30 01:16:44

标签: c++

这是一个学术问题。

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

我知道为什么代码可能无效,但我的其中一条评论有问题:

  

此代码无效,但标准说明在这种情况下不需要诊断,因此两个编译器都符合标准。

为什么标准接受的“无效”代码有效?标准对此案例的具体说明是什么(模板+具有相同名称的类型),并且通常涉及各种实体(类型,模板,函数,变量)的名称空间?

2 个答案:

答案 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-id (名称),但它们(显然)不是同一类型。

所以这里两个方向都存在冲突。 template名称不允许与任何内容冲突,并且typedef不允许将A从模板类类型更改为模板类类型的特化。

答案 1 :(得分:4)

  

为什么标准接受的“无效”代码有效?

不是。如果代码无效,则无效。

应用于语法或语义规则时,短语无需诊断意味着如果您的程序违反规则,编译器不必发出错误消息,并且可以继续编译程序(或者它可以做任何其他事情,真的;如果你给它一个违反这个规则的程序,标准对编译器没有任何要求。)

从某种意义上说,不需要诊断有点像语义规则的未定义行为:如果你违反了不需要诊断的规则,所有的赌注都是关闭。