微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 views::reverse 不适用于 iota_view<int64_t, int64_t>

如何解决为什么 views::reverse 不适用于 iota_view<int64_t, int64_t>

我有 following C++ program,但由于某种原因我不能使用 int64_t 作为模板参数。

#include <iostream>
#include <ranges>

template<typename T> 
void fn() {
    for (auto val : std::ranges::iota_view{T{1701},T{8473}} 
                  | std::views::reverse
                  | std::views::take(5))
    {
        std::cout << val << std::endl;
    }

}

int main()
{
    fn<int16_t>();
    fn<int32_t>();
    // does not compile:
    // fn<int64_t>();
}

这是预期的(我做错了什么),还是只是编译器/标准库中的一些不幸的错误

注意:当我删除 std::views::reverse 时,代码也会为 int64_t 编译。

解决方法

这是一个 libstdc++ 错误,已提交 100639


iota 是一个非常复杂的范围。特别是,我们需要为我们正在递增的类型选择一个足够宽的 difference_type 以避免溢出(另见 P1522)。因此,我们在 [range.iota]:

IOTA-DIFF-T(W) 定义如下:

  • [...]
  • 否则,IOTA-DIFF-T(W) 是宽度大于 W 宽度的有符号整数类型(如果存在此类类型)。
  • 否则,IOTA-DIFF-T(W) 是未指定的类似有符号整数类型 ([iterator.concept.winc]),其宽度不小于 W 的宽度。

[注1:该类型是否满足weakly_­incrementable未明确。 — 尾注]

对于iota_view<int64_t,int64_t>,我们的差分类型是__int128(一个足够宽的有符号整数类型)。在 gcc 上,signed_integral<__int128> 在符合模式 (false) 下编译时为 -std=c++20true 为扩展名 (-std=gnu++20)。

现在,在 libstdc++ 中,reverse_viewimplemented as

template<typename _Iterator>
class reverse_iterator
  : public iterator<typename iterator_traits<_Iterator>::iterator_category,typename iterator_traits<_Iterator>::value_type,typename iterator_traits<_Iterator>::difference_type,typename iterator_traits<_Iterator>::pointer,typename iterator_traits<_Iterator>::reference>
{
  // ...
  typedef typename __traits_type::reference reference;
  // ...
  _GLIBCXX17_CONSTEXPR reference operator*() const;
  // ...
};

这不是 reverse_iterator 的指定方式。 [reverse.iterator]reference 类型定义为:

using reference = iter_reference_t<Iterator>;

区别在于后者仅仅表示*it的类型,而前者实际上通过iterator_traits并试图确定reference如果It::reference不意味着什么' t 作为一种类型存在。该决定在 [iterator.traits] 中指定:

否则,如果 I 满足仅展示概念 cpp17-input-iterator,则 iterator_­traits<I> 具有以下可公开访问的成员:[...]

其中 referenceI::reference(如果存在)或 iter_reference_t<I>(如果不存在)。这看起来是一回事,但我们必须首先满足cpp17-input-iterator<I>。并且 cpp17-input-iterator<I> 要求,其中包括:

template<class I>
concept cpp17-input-iterator =
  cpp17-iterator<I> && equality_­comparable<I> && requires(I i) {
    // ...
    requires signed_­integral<typename incrementable_traits<I>::difference_type>;
  };

所以基本上,iterator_t<iota_view<int64_t,int64_t>> 满足 cpp17-input-iterator 当且仅当 signed_integral<__int128> 成立,这仅在我们在 -std=gnu++20 中编译时才成立。

但是我们不需要满足这个要求,因为reverse_iterator<I>应该直接使用iter_reference_t<I>而不是通过iterator_traits,这需要检查{{1} }.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。