【发布时间】:2021-03-14 00:20:11
【问题描述】:
#include <iostream>
template<typename T>
struct A{
template<typename U>
struct B{};
B<T> b; //#2
};
//#3
int main() {
A<int> a; // #1
}
考虑上面的代码,模板 ID A<int> 的使用会导致专门化 A<int> 的隐式实例化。根据以下规则:
对于类模板特化、类成员模板特化或类模板的类成员的特化,如果该特化是隐式实例化的,因为它是从另一个模板特化中引用的,如果上下文来自引用哪个特化取决于模板参数,如果特化没有在封闭模板的实例化之前被实例化,则实例化点就在封闭模板的实例化点之前。 否则,这种特化的实例化点紧接在命名空间范围声明或引用特化的定义之前。
对于#1 中引用的专业化,该规则的Otherwise 部分将适用于它。这意味着,A<int> 的实例化点应该在#3,这里没有问题。但是,A<int> 的实例化将导致作为其成员的专门化B<int> 的实例化。因此,该规则的 if 部分将适用于 B<int>。我感到困惑的是这里。根据相关规则,B<int>的实例化点应该是紧接在封闭模板的实例化点之前,也就是#3之前的某个地方,我这里看不懂。如果,通过normal class思考,定义其类成员的方式只有两种,一种是在类定义中定义类成员,另一种是在类定义中声明类成员,然后定义类定义之外的类成员在类定义之后的某个点。
使用普通类更改示例:
struct Normal_A_Int{
struct Normal_B_Int{};
Normal_B_Int b;
};
int main(){
Normal_A_Int a;
}
也就是说,成员类Normal_B_Int的定义必须在封闭类的定义中,因为声明Normal_B_Int b需要一个完整的类类型。
那么,如何将成员类B<int> 的定义放在封闭类A<int> 的定义之前?充其量,B<int> 的定义应在A<int> 的定义中。第一个例子的兴趣点如何解释?
【问题讨论】:
-
是否在任何地方指定了“实例化点”的意思是“在该点放置定义”?
-
@LanguageLawyer 该标准并未明确说明这一点,但是,temp.inst#10 规则和 [temp.point#4] 暗示了这一点。
-
@dfrib 是的,对于函数特化,有两个 POI(一个由规则指定,另一个是 TU 的结尾),但是,对于类特化,只有一个 POI 被指定按相关规定。恕我直言,
POI应该用英文理解,即实例化发明的地方,对吧? -
是的,我现在看到[temp.point]/8 在草案中甚至被澄清(现在为 [temp.point]/7),明确指出类模板的专业化最多有一个 POI一个TU。
-
啊,@DavisHerring 是 P1787 的作者!也许他可以说我是否在我的文字答案墙中准确地反映了一些事情。
标签: c++ templates language-lawyer