为什么标准不允许在模板参数列表中初始化常量依赖类型?

Adr*_*ian 34 c++ templates template-meta-programming c++11 c++14

在这篇文章的答案" (部分)专门化依赖类型的非类型模板参数 "中,它指出:

与专用非类型参数对应的模板参数的类型不应取决于特化的参数.[例如:

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
Run Code Online (Sandbox Code Playgroud)

- 末端的例子]

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

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>
{
};
Run Code Online (Sandbox Code Playgroud)

虽然我不确定是否还有其他案例表明基于类型的常量是一个超出没有任何意义的问题.

任何人都有理由说明为何如此?

Nik*_*iou 5

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

  1. 该功能由该语言中的另一种机制涵盖,使其变得多余.
  2. 它与现有的语言逻辑和实现相矛盾,使其实现可能破坏代码.
  3. 遗产:这个特征首先被排除在外,现在我们已经构建了很多,没有它,它几乎被遗忘(参见部分功能模板专业化).

实现的难度很少是一个因素,尽管编译器实现可能需要一些时间才能赶上"硬"内容的演变.

您始终可以将非类型模板参数换行为另一种类型:

template < typename T1, typename T2 > 
struct Demo {}; // primary template

template < typename T > 
struct Demo<T, integral_constant<T, 0>> {}; // specialization
Run Code Online (Sandbox Code Playgroud)

我怀疑这个黑客是否属于案例1.案例3总是有可能所以让我们检查一下案例2.为此,我们必须知道标准对类模板部分特化所施加的相关规则.

14.5.5 类模板部分特化

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

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

    • 除非参数表达式是简单标识符,否则部分专用的非类型参数表达式不应涉及部分特化的模板参数.(C2)
    • 与专用非类型参数对应的模板参数的类型不应取决于特化的参数.(C3)

我标记了我发现相关的前三个C lauses(第三个是有问题的).根据我们的情况C1,我们有一个专门的非类型参数,所以C2应该站立,但这

template <class T, T t> struct C {};
template <class T> struct C<T, 1>;
Run Code Online (Sandbox Code Playgroud)

实际上是

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

所以部分专用的非类型参数T t涉及class T除标识符以外的表达式中的部分特化的模板参数; 此外,这种特殊化必然涉及class T值初始化,这将始终违反规则.然后C3出现并为我们清除,以便我们不必每次都进行扣除.

到目前为止,我们已经确定规则与它们自身同步,但这并不能证明案例2(一旦我们删除了初始限制,其他每个相关限制都会分开).我们必须深入研究匹配的类模板部分特化规则; 部分排序被认为超出了范围,因为如果我们能够生成有效的候选者,则由程序员组成一个格式良好的程序(即不创建类模板的模糊用法).

部分

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

描述模板特化中涉及的(给予或采取)"模式匹配"过程.规则1是过程的整体工作流程,后续规则是定义正确性的规则

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

  2. 还可以从主模板的非类型参数的实际模板参数的值推导出非类型模板参数.

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

通过允许与专用非类型参数对应的模板参数的类型依赖于特化的参数,不违反这些规则.所以恕我直言,没有具体的理由说明为什么我们不能在未来的语言版本中使用这个功能:遗产是罪魁祸首.遗憾的是,我没有找到任何语言提案,主动引入此功能.