考虑一个简单的例子:
int x;
template <template <auto> class TT>
struct Foo {
void foo() {
TT<(x)> tt;
static_cast<void>(tt);
}
};
template <decltype(auto)>
struct Bar { };
int main() {
Foo<Bar> foobar;
foobar.foo();
}
尽管在模板模板参数声明中使用decltype(auto)
没有问题, [clang]似乎也处理了auto
占位符的概念。
[gcc] - 不太好:
prog.cc:6:13:错误:'x'的值在常量表达式中不可用
通常 - 根据标准预期哪种行为?或许一切皆有可能,而且代码格式不正确(这次我想不是,但不能明确地排除它)?
PS。很抱歉再次破坏其中一个编译器;)
答案 0 :(得分:7)
这里的原始答案Foo<Bar>
格式不正确,我现在认为它的格式正确。但最终,基于clang bug。
我实际上认为即使 P0522之后的新规则是:Foo<Bar>
格式不正确。
当P
至少与模板一样专业时, template-argument 匹配模板 template-parameterP
参数A
其中:
模板 template-parameter
P
至少与模板 template-argumentA
一样专业,如果给出以下重写根据函数模板的部分排序规则([temp.func.order]),两个函数模板,对应P
的函数模板至少与对应A
的函数模板一样专用。给定一个发明的类模板X
,其模板参数列表为A
(包括默认参数):
- 两个功能模板中的每一个分别具有相同的模板参数
P
或A
。- 每个函数模板都有一个函数参数,其类型是
X
的特化,其模板参数对应于各个函数模板中的模板参数,其中,模板参数中的每个模板参数PP
在功能模板的列表中,形成了相应的模板参数AA
。如果PP
声明参数包,则AA
是包扩展PP...
([temp.variadic]);否则,AA
是 id-expressionPP
。如果重写产生无效类型,则
P
至少不如A
那么专业。
这意味着要验证Foo<Bar>
本身是否合适,我们合成:
template <decltype(auto) I> struct X;
template <auto I> void __f(X<I> ); // P
template <decltype(auto) I> void __f(X<I> ); // A
此处的所有类型均有效(因此最后一条语句不适用)。现在,通常当我们进行部分排序时,它是在重载决策或选择类模板特化的上下文中,在这种情况下,我们正在寻找的是"more specialized"函数模板,其中F
是{ {3}} G
如果F
至少与G
一样专业,而G
至少与F
一样专业。
但在这种情况下,我们并不关心哪种更专业。我们只需要P
至少与A
一样专业。这意味着扣除必须从A
到P
成功。因此,如果我们合成一些具有某些值U
的唯一类型V
,我们是否可以从X<I>
中推导出X<V>
?是。因此,P
至少与A
一样专业,因此模板参数Bar
与模板参数TT
匹配。
现在,通过这一点,我会说这是一个铿锵的错误。模板 template-parameter 是template <auto>
,这是我们应该用来验证表达式的。对于非类型模板参数auto
,我们尝试使用x
作为值 - 但x
不是有效的常量表达式,因此这应该失败。 clang似乎直接使用template <decltype(auto) >
- 我不确定是否有效。
那就是说,我不确定这个案子是否已被考虑过 - 我没有看到任何措辞,并且值得提出一个问题。