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

时间:2015-03-02 16:40:29

标签: c++ templates

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被视为声明但不是定义这一事实感到困惑。我们在那里提供了函数体,为什么它仍然没有定义?事实上,你无法解释这种解释。

2 个答案:

答案 0 :(得分:3)

这在示例前面的文字中有解释!

  

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

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

答案 1 :(得分:0)

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

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

在此示例中,在包含两个参数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>定义与Outer<int, char>::Inner<int, Y>不同在#1b中定义。