代码之家  ›  专栏  ›  技术社区  ›  Alex B

在C++中声明同名的类型和模板

c++
  •  4
  • Alex B  · 技术社区  · 14 年前

    这是一个学术问题。

    在报告中 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 回复  |  直到 14 年前
        1
  •  10
  •   Tyler McHenry    14 年前

    当标准说“不需要诊断”时,这意味着编译器不必产生关于无效代码的错误或警告,但是根据标准,代码的行为仍然是未定义的,因此它不一定有可预测的结果。这是为了让编译器编写人员更容易操作,这样他们就没有义务检测相对较少或特别麻烦的程序员错误。

    但是,如果违反了“不需要诊断”的规则,则编译器不会 禁止 从检测到无效代码和产生错误作为对用户的礼貌。因此,在给出的示例中,GCC正在为一种特定类型的无效代码生成一个礼貌诊断,而COMEAU正在为类似类型的无效代码生成一个礼貌诊断。但不需要进行任何诊断,因此在任何情况下,其他编译器都不生成错误消息,从而违反了标准。在任何情况下,代码的行为都是未定义的。

    关于类名和模板名的几个相关标准引用:

    3.4/1

    名称查找规则统一应用 所有名称(包括typedef名称) (7.1.3)、命名空间名称(7.3)和 类名(9.1))无论 语法允许在 由特定的人讨论的上下文 规则。名称查找关联使用 具有声明(3.1)的名称 那个名字。名称查找应找到 名称的明确声明 (见10.2)。[…]

    7.1.3/3

    在给定范围中,typedef说明符 不得用于重新定义名称 在该范围内声明的任何类型 请参阅其他类型。例:

    class complex { /* ... */ }; 
    typedef int complex; // error: redefinition
    

    类似地,在给定的 范围、类别或计数应 不能用与相同的名称声明 在中声明的typedef名称 这个范围指的是另一种类型 而不是类或枚举本身。[…]

    91/2

    类定义引入了 类名称进入其所在的作用域 定义并隐藏任何类、对象, 功能或其他声明 封闭范围中的名称(3.3)。如果A 类名称在作用域中声明 对象、函数或 相同名称的枚举器也是 声明,然后当两个声明 在范围内,类可以 仅使用 详细的类型说明(3.4.4)。

    14/5

    类模板不应具有 与其他模板同名, 类、函数、对象、枚举, 枚举器、命名空间或键入 相同范围(3.3),除非另有规定 在(14 5.4)。除了一个函数 模板可以通过 具有相同的(非模板)函数 名称或其他函数模板 同名(14.8.3),a 命名空间中声明的模板名 范围或类别范围应为 在该范围内是唯一的。

    145.4/1

    主类模板声明 是类模板 名称是标识符。模板 类的声明 模板名称是模板ID,是 班的部分专业化 模板中命名的模板-id.a 类的部分专门化 模板提供了另一种选择 模板的定义 使用而不是主定义 当一个专门化中的参数 与部分中给出的匹配 专业化(14.5.4.1)。[…]

    因此,总结如下:

    • typedef s不能更改现有类型的含义
    • class 名称可以与某些类型的名称冲突,但不能与其他类名冲突
    • template 类名不包含模板参数,并且不能与任何内容冲突,即使普通类名允许与之冲突。
    • 模板专门化被认为具有相同的 模板ID (name)作为它们对应的通用模板,但它们(显然)不是同一类型。

    所以这两个方向都有冲突。这个 模板 名称不允许与任何内容冲突,并且 类型定义 不允许更改 A 从模板类类型到模板类类型的专门化。

        2
  •  4
  •   James McNellis    14 年前

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

    不是。如果代码无效,那么它就是无效的。

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

    从某种意义上说, 无需诊断 有点像 未定义的行为 语义规则:如果您违反了不需要诊断的规则,则所有赌注都将取消。