C++20 为别名模板引入 CTAD
别名模板可能确实有默认模板参数,并且按照[temp.param]/14:
如果类模板、变量模板或别名模板的模板参数具有默认模板参数,则每个后续模板参数应提供默认模板参数或模板参数包。 [...]
然而,默认模板参数是一个红鲱鱼,这里的关键是类模板参数推导对于别名模板是否有效,我们可能会将您的示例最小化为以下示例:
#include <tuple>
template <typename T>
using tpl = std::tuple<T>;
tpl x{1}; // should deduce tpl<int> in C++20
// Clang: error
// GCC 9.3: error
// GCC 10.1: ICE / internal compiler error
根据 C++20 接受的P1814R0(1),上面的最小示例确实是合法的,但 Clang 是yet to implement P1814R0,解释了 Clang 拒绝它的原因。另一方面,GCC 将 P1814R0 列为 implemented for GCC 10,这意味着它应该为 C++20 接受它。
(1) 根据 C++20 和 P1814R0(别名模板的类模板参数推导的措辞),(/原提案的措辞 P1021R4)CTAD 是也适用于别名模板,但不允许为它们提供明确的推导指南。
在 C++17 中,您需要在使用别名模板时包含模板参数列表(即使它是空的) - 在 C++17 中,别名模板不等同于类模板参数推导:
#include <tuple>
template <typename T = int, typename... Ts>
using tpl = std::tuple<T, Ts...>;
tpl<> x; // OK in GCC and Clang
无论代码格式错误还是格式正确,ICE(内部编译器错误)始终是错误,如上所述,GCC 仅在 10.1 及更高版本中发出 ICE,而在之前的版本中会产生错误发布。
因此,GCC 显然具有 10.1 的 ICE 回归(在实施别名模板的 CTAD 时,它被可疑地列为目标)。它至少与以下错误报告有关:
然而,这被列为已解决,而您的示例仍然为 GCC 中继生成一个 ICE,其中包含对 96199 的修复。
我们最终可能会注意到,GCC 成功地将 CTAD 应用于我们仅使用模板参数包的别名模板:
#include <tuple>
template <typename... Ts>
using tpl = std::tuple<Ts...>;
tpl x{1}; // OK
但是如果我们在最小示例中将std::tuple 替换为std::vector:
#include <vector>
template <typename T>
using vec = std::vector<T>;
vec x{{1}}; // GCC 10.1: ICE
我们为 GCC 10.1(及更高版本)获得了另一种 ICE,同时接受添加默认模板参数并用默认初始化替换大括号直接初始化。
#include <vector>
template <typename T = int>
using vec = std::vector<T>;
vec x; // GCC 10.1: OK