假设我有一个类/结构模板及其构造函数的明确推导。让此类具有两个模板参数,其中一个可以通过推导指南推导,而另一个则不能。
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<button class="w3-button w3-light-grey w3-large w3-right" onclick="w3_open() "><i class="fa fa-bars"></i></button>
<div class="w3-sidebar w3-bar-block w3-border-left top" style="display:block; width:10%; right:0;" id="mySidebar">
<button onclick="w3_close()" class="w3-bar-item large">Close ×</button>
<a href="#" onclick="q1()" class="w3-bar-item w3-button " id="q1"> 1</a>
<a href="#" onclick="q2()" class="w3-bar-item w3-button" id="q2"> 2</a>
<a href="#" onclick="q3()" class="w3-bar-item w3-button" id="q3"> 3</a>
<a href="#" onclick="q4()" class="w3-bar-item w3-button" id="q4"> 4</a>
</div>
<label class="xxlarge" id="question">
</label><br><br>
<input type="radio" name="choices" value="A" id="r1" class="radio"><label id="c1"></label><br><br>
<input type="radio" name="choices" value="B" id="r2" class="radio"><label id="c2"></label> <br><br>
<input type="radio" name="choices" value="C" id="r3" class="radio"><label id="c3"></label><br><br>
<input type="radio" name="choices" value="D" id="r4" class="radio"><label id="c4"></label><br><br>
<input type="radio" name="choices" value="E" id="r5" class="radio"><label id="c5"></label>
<br>
<br>
<br>
<button onclick="next()" class="btn green round">Save & Next</button>
如果我现在创建一个别名,该别名将显式指定以前不可推导的参数as far as I understand,则该别名的隐式生成推导指南应该能够完全推断出两个模板参数(根据标准模板参数推导的规则),即使在定义的类模板中未推导一种类型。
但是在我不使用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
根据documentation,现在会引入一个非推论上下文(因为模板参数在范围运算符template <int Q, typename F>
Foo(F&& f) -> Foo<Q, typename alias2<F>::type>;
的 left 中出现),因此template参数对::
的推论应该失败(显然是does)。
问题1:如果这个理论是正确的,那么我能做些什么?假设我不想使用琐碎的身份别名,而是使用一个更复杂的类型转换,该类型转换最终将在推导指南中具有T=F
的形状。
问题2:即使是现在,当我完全删除Q时,我的理论仍然失败,因为以下代码将被接受(GCC-10 / 11):
typename transformation<Input>::result
即使这是一个非推论上下文,为什么编译器还能从F推导出T?
答案 0 :(得分:2)
要执行所需的操作,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 ++语言有很多措辞,允许模板别名只是重命名参数或类似名称,就像它们在原始类型中一样。最初,甚至一个玩具别名也会阻止很多这种推论。但这被认为是一个坏计划。因此,他们在标准中添加了文字,以描述“琐碎”之类的模板别名,并修改了演绎规则的措词,以便将其视为透明。
要在类型推导过程中反转任意图灵完备的程序(实际上,几乎是任何结构上不重要的类型转换),必须显式进行反转。
一旦您接受了它,就变成了语法问题,而不是概念问题。
我不知道别名模板的用户定义模板推导指南的当前状态。上次我听说它不受支持,但最近没有检查。