为什么 C++ span 的 C 样式数组构造函数需要type_identity_t?

Why does C++ span's C style array constructor need type_identity_t?

提问人:cbhattac 提问时间:6/14/2023 更新时间:6/14/2023 访问量:105

问:

span 的 C 样式数组构造函数指定如下

template<size_t N> constexpr span(
   type_identity_t<element_type> (&arr)[N]) noexcept;

为什么有必要?而不仅仅是:type_identity_t

template<size_t N> constexpr span(
   element_type (&arr)[N]) noexcept;

正如本提案中最初定义的那样?

C++ C++20 CTAD 标准跨度

评论


答:

1赞 Yakk - Adam Nevraumont #1

正如 cbhattac 的回答所解释的那样,问题在于 span 的推导指南选择了错误的超载。

issue3369 中,开发了一个修复程序。

核心问题是:

template <size_t Size>
  requires (Extent == dynamic_extent || Extent == Size)
span(T (&)[Size]) {}

CTOR 生成隐式演绎指南,也是如此

template <typename T, size_t Extent>
span(T (&)[Extent]) -> span<T, Extent>;

构造函数构建一个具有可变长度的构造函数,而推导指南构建一个具有固定长度的构造函数。span

当传递一个固定长度的数组时,理想的推导跨度也应该是固定长度的。但这并没有发生。

天真地,显式演绎公会击败了构造函数生成的公会,但事实并非如此——由于子句,这里的构造函数受到的约束更大。所以它击败了扣除指南。requires (Extent == dynamic_extent || Extent == Size)

为了解决这个问题,用于完全阻止此构造函数的CTAD。(另一种可行的方法是在扣除指南中添加一个微不足道的约束)。type_identity_t<T>