如何在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++标准没有让编译器尝试尝试来反转这样的计算,而是统一地说&不要尝试";。它通常使用依赖类型&来阻止此类反转尝试。

在第二种情况下,BarFoo的一个普通别名。Foo有扣款指南。该演绎指南说明了如何从FT,因此编译器不必颠倒任何潜在的图灵完成程序来确定T

C++语言有一堆措辞,允许只是重命名参数或类似的模板别名就像它们是原始类型一样。最初,即使是一个玩具别名也会阻止一大堆这种扣除;但这被发现是一个糟糕的计划。因此,他们在标准中添加了描述哪种模板别名的文本,并修改了扣减规则的措辞,使其被视为透明。


为了在类型演绎过程中反转任意图灵完成程序(实际上,几乎任何结构上的非平凡类型转换),您必须显式地给出反转。

一旦你接受了这一点,它就变成了与语法的斗争,而不是与概念的斗争。

我不知道别名模板的自定义模板扣款指南的当前状态。上次我听说它不受支持,但我最近没有检查过。

相关文章