使用非类型模板参数 decltype(auto) 的类模板的部分特化

问题描述 投票:0回答:1

在下一个示例程序中,具有非类型模板参数

decltype(auto)
的类模板部分专用于非类型模板参数
auto
:

template <decltype(auto)>
struct A { static const int v = 0; };

template <auto n>
struct A<n> { static const int v = 1; };

并且它被所有编译器接受,只有 GCC 发出警告

warning: partial specialization 'struct A<n>' is not more specialized than
note: primary template 'template<decltype(auto) <anonymous> > struct A'

以下断言是否正确(如 Clang 中所示)?

const int i = 0;
static_assert( A<i>::v == 1 );  //ok everywhere
static_assert( A<(i)>::v == 0 );//ok in Clang only

据我了解,这里Clang中的

A<(i)>
选择了参数类型为
const int&
的主类模板,所以
A<(i)>::v == 0
。而 Clang 中的
A<i>
选择参数类型为
int
的特化,因此
A<i>::v == 1

但是GCC和MSVC不同意,他们在这两种情况下都选择了专业化,所以

A<(i)>::v == 1
。在线演示:https://godbolt.org/z/Wfd8e1KPz

根据标准,这里哪个编译器是正确的?

c++ templates language-lawyer auto partial-specialization
1个回答
0
投票

我们必须按照 [temp.spec.partial.general]/9.2 的要求检查部分特化实际上是否比主模板更特化。 (据我所知,Clang 还没有实现这个规则,所以实际上,Clang 并没有对这个问题发表任何意见。)

[temp.spec.partial.order]解释了如何在两个部分专业化之间执行“更专业”的比较(我们必须将主模板视为也是部分专业化):我们必须将它们重写为函数模板每个都将类模板作为其唯一参数:

template <decltype(auto) x>
void f(A<x>);  // (1)

template <auto x>
void f(A<x>);  // (2)

然后我们必须应用 [temp.func.order] 来对这两个函数模板进行排序。第 3-4 段中解释的基本规则是,为了检查 (2) 是否比 (1) 更专业,我们必须为 (2) 中

auto
x
类型合成一个唯一类型和一个唯一值对于
x
本身,将其替换为该类型的
x
到声明 (2) 中,并尝试从结果函数类型中推导出 (1)。

但是我们有一个问题,因为实际上并不清楚代入(2)会产生什么(如果有的话)。让我们仔细阅读第3页:

为了生成转换后的模板,对于每个类型、非类型或模板模板参数(包括其模板参数包)分别合成一个唯一的类型、或类模板,并将其替换为该参数的每次出现模板的函数类型.

void f(A<x>)
中,我们到底用什么来替代
x
?独特的价值。但这个值有什么特点呢?它是否是一个 id-expression(导致
decltype(auto)
推导出其声明的类型)?如果它不是 id-expression,那么它是左值还是纯右值?这会影响
decltype(auto)
是否被推导为引用类型或非引用类型。如果将其推导为引用类型,则适用其他限制,这可能会使替换的 template-id 无效。然后会发生什么?部分排序规则没说。

在这一点上,我确信我们在标准中的部分排序规范上存在严重问题,而且我们还不知道如何解决。对不起。我的建议是不要专门化具有

decltype(auto)
模板参数的模板。

© www.soinside.com 2019 - 2024. All rights reserved.