对应于模板中的定义的声明

Declaration that corresponds to a definition in a template

本文关键字:定义 声明 于模板      更新时间:2023-10-16

N4296::14.7.1/1 [temp.inst]提供了以下示例:

template<class T, class U>
struct Outer {
    template<class X, class Y> struct Inner;
    template<class Y> struct Inner<T, Y>; // #1a
    template<class Y> struct Inner<T, Y> { }; // #1b; OK: valid redeclaration of #1a
    template<class Y> struct Inner<U, Y> { }; // #2
};
Outer<int, int> outer; // error at #2

并给出以下解释:

Outer<int, int>::Inner<int, Y>#1b重新声明。(它不是 已定义,但注明与 中的定义相关联 Outer<T, U> .( #2也是对#1a的重新声明。它被指出为 与定义相关联,因此它是相同的无效重新声明 部分专业化。

我对#1b被视为宣言而不是定义这一事实感到困惑。我们在那里明确提供了函数体,为什么它仍然不是一个定义?事实上,你无法解释这种兴奋吗?

这在示例前面的文本中进行了解释!

类模板专用化的隐式实例化会导致类成员函数、成员类、作用域成员枚举、静态数据成员和成员模板的定义或默认参数的隐式实例化

,但不是定义或默认参数的隐式实例化;它会导致无作用域成员枚举和成员匿名联合的定义隐式实例化。但是,为了确定成员的实例化重新声明是否根据 9.2 有效,与模板中的定义对应的声明被视为 定义。

实例化模板产生的函数定义与函数模板本身的定义之间存在差异。

名称通过其第一个声明引入其范围,然后与对象、函数或类等实体相关联。在某些作用域(如命名空间作用域或类作用域(中,可以多次声明名称。名称声明还可以包括命名实体的定义。在看到定义之后,据说有关声明与定义相关联。命名实体不允许使用多个定义。

隐式实例化类模板时,不会立即实例化其嵌套函数、类和静态对象成员的定义。它们仅在需要时立即实例化。但是,有一个特殊的规则可以捕获潜在的定义冲突。

在此示例中,在具有两个参数 TU 的类模板中,声明了具有两个参数 XY 的内部类模板。为内部类定义了两个部分专用化,一个用于XT重合的情况,另一个用于XU重合的情况。第一个部分专业化首先在 #1a 声明,然后在 #1b 重新声明并与定义相关联。声明第二个部分专用化并与 #2 处的定义相关联。

目前为止,一切都好。

但是,如果TU是同一类型,例如int呢?在这种情况下,对于任何给定的Y,#1a、#1b 和 #2 中的声明都声明相同的名称 Outer<int, int>::Inner<int, Y> 。其中两个声明与定义相关,这会导致冲突。您引用的 N4296 中的示例是为了证明即使没有需要实例化Outer<int, int>::Inner<int, Y>的引用,也必须诊断冲突。

Outer<int, char>很好,因为在这种情况下,TU不一致,因此 #2 为Outer<int, char>::Inner<char, Y>提供了与 #1b 中定义的Outer<int, char>::Inner<int, Y>不同的定义。