如何在C++20中创建模板别名的推导指南

How can I create deduction guides for template aliases in C++20?

本文关键字:别名 建模 C++20 创建      更新时间:2023-10-16

假设我有一个类/结构模板及其构造函数的显式推导指南。让这个类有两个模板参数,一个可以由推导指南推导,另一个不能。

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 };
}

如果我现在创建一个别名,它将显式指定以前不可减少的参数,据我所知,该别名的隐式生成的推断指南应该能够完全推断出两个模板参数(通过标准模板参数推断规则(,即使在定义类模板中有一个类型是不可减少。

但是,在我不使用alias,而是使用alias2的情况下,我能做什么,即将推导指南更改为

template <int Q, typename F>
Foo(F&& f) -> Foo<Q, typename alias2<F>::type>;

根据文档,这将引入一个非推导上下文(因为模板参数出现在作用域运算符::的左侧(,所以T=F的模板参数推导应该失败(显然是这样(。


问题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>;

需要反转第二个模板参数CCD_ 7以找到CCD_。当alias是一个琐碎的模板别名时,这是可能的、允许的,也是C++标准所要求的。

alias2评估为foo<F>::type时,这样的构造能够实现完全计算。C++标准不是让编译器尝试来反转这样的计算,而是统一地说";不要尝试"。它使用";依赖型";通常是为了阻止这种反转尝试。

在第二种情况下,BarFoo的一个微不足道的别名。Foo有一个推导指南。推导指南告诉如何从FT,因此编译器不必为了确定T而反转任何潜在的图灵完备程序。

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


为了在类型推导过程中反转任意图灵完备程序(事实上,几乎是任何结构上非平凡的类型转换(,必须显式给出反转。

一旦你接受了这一点,它就变成了语法之战,而不是概念之战。

我不知道别名模板的自定义模板推导指南的现状。上次我听说它不受支持,但我最近没有检查。