为什么标准中不允许初始化模板参数列表中的常量相关types?

在对这篇文章的回答“ (部分地)专门化非依赖types的非types模板参数 ”中,它指出:

对应于专门的非types参数的模板参数的types不应该依赖于专门化的参数。 [例如:

template <class T, T t> struct C {}; template <class T> struct C<T, 1>; // error template< int X, int (*array_ptr)[X] > class A {}; int array[5]; template< int X > class A<X,&array> { }; // error 

– 例子]

我的问题是为什么这个限制在这里? 至less有一个用例,我发现这个限制干扰了编写干净的代码。 例如

 template <typename T, T*> struct test; template <typename T> struct test<T, nullptr> // or struct test<T, (T*)nullptr> { }; template <typename R, typename...ARGs, R(*fn)(ARGs...)> struct test<R(ARGs...), fn> { }; 

虽然我不确定是否还有其他一些基于types的常量是不成问题的问题。

任何人都有这样的原因吗?

(恕我直言)标准不允许某个特定function的最常见的原因是:

  1. 该function被另一种语言机制所覆盖,使其变得多余。
  2. 它与现有的语言逻辑和实现相矛盾,使得它的实现有可能破译。
  3. 遗产:这个function首先被排除在外,现在我们已经build立了很多没有它的function,几乎被遗忘了(请参阅部分function模板专门化)。

实现的难度很less是一个因素,尽pipe编译器实现可能需要一些时间才能赶上“硬”东西的进化。

您始终可以将您的非types模板参数封装在另一个types中:

 template < typename T1, typename T2 > struct Demo {}; // primary template template < typename T > struct Demo<T, integral_constant<T, 0>> {}; // specialization 

我怀疑这种攻击是否属于案例1.案例3总是一种可能性,所以我们来看案例2.为此,我们必须知道标准对类模板部分专业化的相关规则。

14.5.5 类模板部分专业化

  1. 如果非types参数是非types参数的名称,则它是非专用的。 所有其他非types的参数都是专门的。 (C1)

  2. 在类模板部分特化的参数列表中,下列限制适用:

    • 除非参数expression式是简单标识符,否则部分专用的非types参数expression式不应包含部分特化的模板参数。 (C2)
    • 对应于专门的非types参数的模板参数的types不应该依赖于专门化的参数。 (C3)

我标出了我认为相关的前三位C (第三位是有问题的)。 根据我们的情况C1, 我们有一个专门的非types的论点,所以C2应该站立,但这

 template <class T, T t> struct C {}; template <class T> struct C<T, 1>; 

实际上是

 template <class T, T t> struct C {}; template <class T> struct C<T, T(1)>; // notice the value initialization 

所以部分专用的非types参数T t在除标识符以外的expression式中涉及部分专用化class T的模板参数; 而且这样的专业化必然涉及到class T的价值初始化,这将永远是违反规则的。 然后C3出现,为我们清除了这个问题,这样我们就不用每次都去扣除了。

到目前为止,我们已经确定规则与他们自己同步,但是这不能certificate情况2(一旦我们删除了最初的限制,其他所有相关的限制就会分崩离析)。 我们不得不深入匹配类模板的部分特殊化规则; 部分sorting在这里被认为是超出范围的,因为如果我们能够产生有效的候选者,那么由程序员来组装一个合适的程序(即不会产生类模板的模棱两可的用法)。

部分

类模板部分特化的匹配[temp.class.spec.match]

描述了在模板专门化中涉及(给与或带)的“模式匹配”过程。 规则1是程序的总体工作stream程,后面的规则是定义正确性的规则

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

  2. 非模板参数也可以从主模板的非types参数的实际模板参数的值中推导出来。

  3. 在引用类模板专业化的types名称(例如A)中,参数列表应与主模板的模板参数列表相匹配。 专业化的模板参数是从主模板的参数中推导出来的。

通过允许对应于特定非types参数的模板参数的types依赖于特化的参数, 这些规则不被违反 。 所以恕我直言,没有具体的理由,为什么我们不能在这个语言的未来版本中有这个function: 遗产是责备 。 可悲的是,我没有设法find任何语言的build议,主动介绍这个function。