如何在C++20中创建模板别名的推导指南
How can I create deduction guides for template aliases in 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 };
}
如果我现在创建一个别名,它将显式指定以前不可减少的参数,据我所知,该别名的隐式生成的推断指南应该能够完全推断出两个模板参数(通过标准模板参数推断规则(,即使在定义类模板中有一个类型是不可减少。
但是,在我不使用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++标准不是让编译器尝试来反转这样的计算,而是统一地说";不要尝试"。它使用";依赖型";通常是为了阻止这种反转尝试。
在第二种情况下,Bar
是Foo
的一个微不足道的别名。Foo
有一个推导指南。推导指南告诉如何从F
到T
,因此编译器不必为了确定T
而反转任何潜在的图灵完备程序。
C++语言有一堆措辞,允许模板别名只是参数的重命名或类似操作,就像它们是原始类型一样。最初,即使是一个玩具别名也会阻止一堆这种推导;但人们发现这是一个糟糕的计划。因此,他们在标准中添加了文本来描述什么样的模板别名;琐碎的";并修改了扣除规则的措辞,使其被视为透明的。
为了在类型推导过程中反转任意图灵完备程序(事实上,几乎是任何结构上非平凡的类型转换(,必须显式给出反转。
一旦你接受了这一点,它就变成了语法之战,而不是概念之战。
我不知道别名模板的自定义模板推导指南的现状。上次我听说它不受支持,但我最近没有检查。
- 部分定义/别名模板模板参数
- 如何在C++20中创建模板别名的推导指南
- 告诉c++编译器该参数没有别名
- boost::spirit::karma 替代生成器,带有 boost::variant 由字符串和字符串别名组成
- 继承模板类中的类型别名
- 别名模板的专业化 C++11 中没有开销的最佳替代方案
- 为什么 GCC 在使用类型别名时处理 const reinterpret_cast不同?
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 为什么我们不能重复使用具有不同模板参数的别名模板标识符?
- C++模板/别名 - 模板参数列表中参数 1 处的类型/值不匹配
- 如何使用类型别名从模板化类中隐藏模板列表
- 满意和建模的概念?
- 模板模板参数和模板别名:编译器错误?
- 使用定义函数模板别名
- 为模板参数包添加别名
- 如何检测类型类型别名?
- C++类型别名,其中值被替换
- C++使用默认模板参数键入别名和转发声明
- 在Qt中注册自定义元类型的别名类型
- 缺少别名模板C++参数列表