【问题标题】:Can alias templates have default template parameters?别名模板可以有默认模板参数吗?
【发布时间】:2021-01-12 17:15:42
【问题描述】:

以下代码很短,但会导致不同的编译器表现出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 有一个internal compiler error。我通常会认为别名模板不会被扣除 - 特别是根据cppreference 他们没有(我知道这不是官方资源,只是一个参考) - 但是我想确定。

这段代码真的格式不正确还是这些编译器还没有实现别名模板默认模板参数?我以为它们是在 C++17 或 C++20 中添加的。

【问题讨论】:

  • 默认模板参数有效 - 你应该输入tpl&lt;&gt; x。这与模板类型推导不同,实际上别名不存在。
  • @bloody 它们已为 C++20 (P1814R0) 添加。

标签: c++ templates language-lawyer alias


【解决方案1】:

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

【讨论】:

  • 谢谢!似乎这段代码在 GCC 下编译:` template using vec = std::vector; vec x;` 但是std::tuple 却没有。这可能是 GCC 错误吗?
  • @therapy_3d_graphics_pr... GCC 似乎在这里有某种 ICE 错误(请参阅我的更新答案);即使在别名模板中使用默认模板参数并为默认初始化变量尝试 CTAD 也应该是可行的(因为默认模板参数被带到 CTAD 用于推导的发明函数模板中)。
猜你喜欢
  • 2014-11-06
  • 2018-10-12
  • 2012-06-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-06
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
相关资源
最近更新 更多