如何在C++20中为模板别名创建扣减指南?
假设我有一个类/结构模板及其构造函数的显式推导指南。让这个类有两个模板参数,其中一个可以通过演绎指南推导,另一个不能。
template <int Q, typename T>
struct Foo {
template <typename F>
Foo(F&&) { }
};
template <typename T>
using alias = T;
template <typename T>
struct alias2 { using type = T; };
template <int Q, typename F>
Foo(F&& f) -> Foo<Q, alias<F>>; // deduction guide, but cannot deduce Q yet
template <typename T>
using Bar = Foo<1, T>; // create alias that fixes Q
/* This should generate a deduction guide for Bar<T> by first
"copying" Foo's deduction guide, deducing from Foo<Q, alias<F>>
and Foo<1, T> that Q=1 and T=alias<F>=F, thus generating
<template F>
Bar(F&&) -> Bar<1, F>;
if this was correct syntax. */
int main() {
Bar f{ 5 };
}
如果我现在创建一个别名,该别名将显式指定以前不可演绎的参数as far as I understand,则该别名的隐式生成的演绎指南应该能够完全演绎两个模板参数(根据标准模板实参演绎的规则),即使在定义类模板中没有演绎一个类型。
但是如果我不使用alias
,但使用alias2
,即将扣款指南更改为
template <int Q, typename F>
Foo(F&& f) -> Foo<Q, typename alias2<F>::type>;
根据documentation,这现在将引入一个非演绎的上下文(因为模板参数对作用域操作符::
显示为左侧),因此T=F
的模板参数推导应该失败(这显然是does)。
问题1:如果这个理论是正确的,我能做些什么吗?假设我不想使用简单的身份别名,而是一个更复杂的类型转换,在演绎指南中最终将具有typename transformation<Input>::result
的形状。
问题2:即使是现在,当我完全删除q时,我的理论仍然失败,因为以下代码将被接受(GCC-10/11):
template <typename T>
struct Foo {
template <typename F>
Foo(F&&) { }
};
template <typename T>
struct alias2 { using type = T; };
template <typename F>
Foo(F&& f) -> Foo<typename alias2<F>::type>;
template <typename T>
using Bar = Foo<T>;
template <typename T>
void some(typename alias2<T>::type) { }
int main() {
Bar f{ 5 };
}
为什么即使这是非推导的上下文,编译器也能够从F推导出T?
解决方案
若要执行所需操作,C++必须能够反转图灵完成子程序。
图灵完成程序不仅是不可逆的,而且不可能确定给定的图灵完成程序是否可逆。您可以定义子语言,其中它们都是可逆的,但这些子语言缺乏图灵完全能力。推导Bar
别名参数:
template <typename T>
using Bar = Foo<1, T>;
需要反转第二个模板参数alias<F>
以找到F
。当alias
是微不足道的模板别名时,这是可能的,也是C++标准所允许和要求的。
当alias2
求值为foo<F>::type
时,这样的构造能够进行图灵完全计算。C++标准没有让编译器尝试尝试来反转这样的计算,而是统一地说&不要尝试";。它通常使用依赖类型&来阻止此类反转尝试。
在第二种情况下,Bar
是Foo
的一个普通别名。Foo
有扣款指南。该演绎指南说明了如何从F
到T
,因此编译器不必颠倒任何潜在的图灵完成程序来确定T
。
C++语言有一堆措辞,允许只是重命名参数或类似的模板别名就像它们是原始类型一样。最初,即使是一个玩具别名也会阻止一大堆这种扣除;但这被发现是一个糟糕的计划。因此,他们在标准中添加了描述哪种模板别名的文本,并修改了扣减规则的措辞,使其被视为透明。
为了在类型演绎过程中反转任意图灵完成程序(实际上,几乎任何结构上的非平凡类型转换),您必须显式地给出反转。
一旦你接受了这一点,它就变成了与语法的斗争,而不是与概念的斗争。
我不知道别名模板的自定义模板扣款指南的当前状态。上次我听说它不受支持,但我最近没有检查过。
相关文章