在对这篇文章“(Partially) specializing a non-type template parameter of dependent type”的回答中,它指出:
与专门化相对应的模板参数的类型 非类型参数不应该依赖于参数 专业化。 [例如:
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
-end example]
我的问题是为什么这个限制在这里?至少有一个用例,我发现这个限制干扰了编写干净的代码。 E.g。
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>
{
};
虽然我不确定是否还有其他案例根据类型声明一个常数是一个超出无意义的问题。
任何人都有理由说明为何如此?
答案 0 :(得分:5)
(恕我直言)标准不允许特定功能的最常见原因是:
实现的难度很少是一个因素,尽管编译器实现可能需要一些时间来赶上“硬”内容的演变。
您始终可以将非类型模板参数换行为另一种类型:
template < typename T1, typename T2 >
struct Demo {}; // primary template
template < typename T >
struct Demo<T, integral_constant<T, 0>> {}; // specialization
我怀疑this hack属于案例1.案例3始终是可能的,所以让我们检查案例2.为此,我们必须知道标准对类模板部分特化所施加的相关规则。
14.5.5 类模板部分特化
如果非类型参数是非类型参数的名称,则它是非专用的。所有其他非类型参数都是专用的。的(C1)
在类模板部分特化的参数列表中,以下限制适用:
- 部分专用的非类型参数表达式不应涉及部分特化的模板参数,除非参数表达式是简单标识符。的(C2)
- 与专用非类型参数对应的模板参数的类型不应取决于特化的参数。的(C3)
我标记了我发现相关的前三个 C lauses(第三个是有问题的)。根据我们案例中的C1 我们有一个专门的非类型参数所以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
因此,部分专用的非类型参数T t
涉及除标识符之外的表达式中的部分特化class T
的模板参数;此外,这些特化必然会在值初始化中涉及class T
,这将始终违反规则。然后C3出现并为我们清除,以便我们不必每次都进行扣除。
到目前为止,我们已经确定规则与他们自己同步,但这并不能证明案例2(一旦我们删除了初始限制,每隔一个相关的限制就会分开)。我们必须深入研究匹配类模板部分特化规则;在这里,部分排序被认为超出了范围,因为如果我们能够生成有效的候选者,那么由程序员组成一个格式良好的程序(即不创建类模板的模糊用法)。
部分
匹配类模板部分特化[temp.class.spec.match]
描述了模板专业化中涉及的“给予或采取”“模式匹配”过程。规则1
是过程的整体工作流程,后续规则是定义正确性的规则
如果可以从实际模板参数列表推导出部分特化的模板参数,则部分特化匹配给定的实际模板参数列表
还可以从主模板的非类型参数的实际模板参数的值推导出非类型模板参数。
在引用类模板特化的类型名称中(例如,A),参数列表应与主模板的模板参数列表匹配。专业化的模板参数是从主模板的参数中推导出来的。
不违反这些规则允许与专用非类型参数对应的模板参数的类型依赖于特化的参数。所以恕我直言没有具体原因为什么我们在未来的语言版本中不能拥有此功能:遗产应该归咎于。遗憾的是,我没有找到任何语言提案,主动引入此功能。