繁体   English   中英

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

[英]Why does views::reverse not work with iota_view<int64_t, int64_t>

我有以下 C++ 程序,由于某种原因,我不能使用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)是一个带符号的 integer 类型,其宽度大于W的宽度(如果存在这种类型)。
  • 否则, IOTA-DIFF-T(W)是未指定的带符号整数类型 ([iterator.concept.winc]),其宽度不小于W的宽度。

[注 1:未指定此类型是否满足weakly_incrementable ——尾注]

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

现在,在 libstdc++ 中, reverse_view 实现为

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并尝试确定如果It::reference作为类型不存在时reference的含义。 该确定在[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>;
  };

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM