以下代码非常短,但会导致不同的编译器表现 disagree :
#include <tuple>
template <typename T = int, typename... Ts>
using tpl = std::tuple<T, Ts...>;
tpl x; // I would assume this should be std::tuple<int>
Clang 和 MSVC 表示模板参数推导不适用于别名模板,ICC 表示模板参数丢失,而 GCC 存在内部编译器错误
。我通常会认为别名模板不进行扣除的指示 - 特别是根据cppreference他们没有(我知道这不是官方资源,只是引用) - 但我想确定一下。
这段代码真的格式不正确,还是别名模板默认模板参数根本尚未在这些编译器中实现?我以为它们是在 C++17 或 C++20 中添加的。
最佳答案
C++20 引入了用于别名模板的 CTAD
别名模板确实可能具有默认模板参数,并且将默认模板参数设置为后跟模板参数包的模板参数是合法的,如 [temp.param]/14 所示。 :
If a template-parameter of a class template, variable template, or alias template has a default template-argument, each subsequent template-parameter shall either have a default template-argument supplied or be a template parameter pack. [...]
但是,默认模板参数是一个红鲱鱼,这里的关键是类模板参数推导对于别名模板是否有效,我们可以将您的示例最小化为以下示例:
#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
根据 P1814R0 (1),已被 C++20 接受,上面的最小示例确实是合法的,但 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 时,它被可疑地列为目标)。它至少与以下错误报告有关:
- Bug 96199 - [10/11 Regression] internal compiler error: in tsubst_copy with CTAD for alias templates
然而,它被列为已解决,而您的示例仍然为 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
关于c++ - 别名模板可以有默认模板参数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65688740/