c++ - 别名模板可以有默认模板参数吗?

标签 c++ templates language-lawyer alias

以下代码非常短,但会导致不同的编译器表现 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 时,它被可疑地列为目标)。它至少与以下错误报告有关:

然而,它被列为已解决,而您的示例仍然为 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/

相关文章:

c++ - 带 boost 的大整数:太大而无法以任何整数类型表示

c++ - 将变量的指针作为基于模板的参数传递

c++ - boost::function 的多个 typedef 的容器

c++ - 我们能否将规范性引用中未明确引用的内容应用于 C++ 标准?

c++ - 警告 C5246 : the initialization of a subobject should be wrapped in braces

c++ - 使用模板转换运算符解决歧义

c++ - 如何从用户那里获取整数输入,直到在 C++ 中遇到输入

c++ - 我想计算 char* word_list[] (C++) 中的字符串数量

c++ - 如何附加到 C++ 预处理器宏?

c++ - 替代网络框架上的显式实例化