【问题标题】:Matching of class template partial specializations类模板偏特化的匹配
【发布时间】:2015-08-31 21:30:50
【问题描述】:

N4527 14.5.5.1[temp.class.spec.match]

2 如果部分特化的模板参数可以从实际模板参数列表中推导出来,则部分特化匹配给定的实际模板参数列表。

template<class T1, class T2, int I> class A             { }; // #1
template<class T, int I>            class A<T, T*, I>   { }; // #2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
template<class T>                   class A<int, T*, 5> { }; // #4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5

A<int, int, 1>   a1; // uses #1
A<int, int*, 1>  a2; // uses #2, T is int, I is 1
A<int, char*, 5> a3; // uses #4, T is char
A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1
A<int*, int*, 2> a5; // ambiguous: matches #3 and #5

3 非类型模板实参也可以从主模板的非类型形参的实际模板实参的值推导出来。 [例子:上面a2的声明。 —结束示例]

4 在引用类模板特化的类型名称中(例如,A&lt;int, int, 1&gt;),参数列表应 匹配主模板的模板参数列表。特化的模板参数是 从主模板的参数推导出来。

在规则3中,示例显示I是从第三个实际模板参数1推导出来的,这就是规则2所说的。所以作为rule4的第二句,我认为它是在重复rule2所说的。

它们之间有什么区别(rule2、rule3和rule4)?

也就是说,我们已经有了rule2,rule3和rule4第二句的意图(意义)是什么,为什么会出现在这里?

【问题讨论】:

  • 显然这个措辞已经出现在long time
  • @Barry 做一些标准考古,它似乎已经在N0668(1995 年 3 月)中引入。因此,在您引用的N1043(1996 年 12 月)之间的某个地方,必须详细说明该示例。不幸的是,并非所有工作文件草稿都在线。特别是,N0836 可能是相关的。
  • @TemplateRex 我认为规则 4 的第一句话说,在引用类模板特化的类型名称中,参数列表不能使用部分特化的模板参数列表,它应该匹配主模板的模板参数列表。例如A&lt;int,1&gt; a2 是错误的。对于第二句,我不知道它和规则2的区别。
  • 我会说规则 3 是对规则 2 的澄清。它所说的 规则 2 不仅适用于类型,也适用于非类型模板参数。规则 2 隐含地包含“非类型模板参数”,但规则 3 明确指出。
  • @EugeneZavidovsky 也许使用 simple-template-id 作为 A 并使用 template-name 后跟隐式模板参数列表作为 P,使用规则 14.8 .2.5 [temp.deduct.type]。例如A&lt;int, int*, 1&gt; a2;A&lt;int, int*, 1&gt; 作为 A,A&lt;T1, T2, I&gt; 作为 P。

标签: c++ templates language-lawyer


【解决方案1】:

我认为,规则 [temp.class.spec.match] 14.5.5.1\2 可以这样重写而不改变其主旨:

[temp.class.spec.match] 14.5.5.1\2(修改)

部分特化匹配给定的实际模板参数列表 如果可以推导出偏特化的模板参数 根据 14.8.2.5 来自实际模板参数列表,其中 P 是其偏特化的参数列表 simple-template-id 并且 A 是实际的模板参数列表。

规则 [temp.deduct.type] 14.8.2.5\1 仅定义了从类型推导的过程(虽然我不确定模板),因此需要规则[temp.class.spec.match] 14.5.5.1\3,增加了主模板的非类型模板参数的 14.5.5.1\2 案例,其中不(部分)专门从事部分专业化。

规则 [temp.class.spec.match] 14.5.5.1\4,正如您在上面的 cmets 中所指出的(12),只是为了澄清,即template-id 中的模板参数对应于主模板的模板参数,而不是它的部分特化,它可能有不同的 template-parameter-list。此外,规则的第二句很可能声称主模板 (14.5.5\4) 的隐式模板参数列表是根据 [temp.deduct. type] 14.8.2.5\9 来自实际参数列表。所以短语“主模板的隐式模板参数列表”和“专业化的模板参数”暗示了一个相同的东西,短语“主模板的参数”和“实际模板参数列表”暗示了另一个相同的东西...但也可能是作者打算写这个:

[temp.class.spec.match] 14.5.5.1\4(修改)

在引用类模板特化的类型名称中,实参列表应与主模板的模板形参列表匹配。部分特化的模板参数是从主模板的参数推导出来的。

随便...

【讨论】:

  • 换句话说,也可能是作者在 14.5.5.1 中通过短语“专业化的模板参数”暗示了“部分专业化的模板参数” \4。 Bingo?
【解决方案2】:

规则二和规则四的区别在于第二个和第三个模板参数。例三:

A&lt;int, char*, 5&gt; a3; // uses #4, T is char

它使用 rule4 是因为第三个参数明显专门用于 const int 5,而第二个参数专门用于接受指针类型;它是class A 的独特专业化。

我将每个专业化视为类的特定物种,每个物种都有一个独特的签名(类似于重载函数)。编译器将选择与正在使用的签名匹配的专业化。

规则三只有在没有规则五的情况下才有意义,所以在删除规则五后,规则三的意图是专门化 class A 的任何类型名: a) do not use a const int 5 for the third parameter b) do not use a pointer or as the second parameter c) do not use a `int` in the second parameter.

由于您的示例均未使用 rule3 的唯一签名,因此它们均未使用 rule3(假设我们删除了模棱两可的 rule5)。

如果您只查看专业化的template&lt;...&gt; 方案而不是专业化的签名&lt;&gt;,这可能会更好地理解。编译器在查看专业化之前查看模板方案。此外,class A 的所有其他专业化定义了任何新专业化的规则。要了解专业化的意图,您必须了解所有其他专业化的意图,并且专业化的意图不是由标准定义的,而是由实施专业化的人定义的; IE。专业化的实现细节真正定义了意图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多