【问题标题】:Why does std::get only have two function overloads for ranges::subrange?为什么 std::get 只有两个 range::subrange 函数重载?
【发布时间】:2021-09-06 16:29:25
【问题描述】:

标准中有四种pair-like类型,分别是std::arraystd::pairstd::tupleranges::subrange,其中std::getranges::subrange的重载在[range.subrange#access-10]中定义:

template<size_t N, class I, class S, subrange_kind K>
  requires (N < 2)
  constexpr auto get(const subrange<I, S, K>& r);
template<size_t N, class I, class S, subrange_kind K>
  requires (N < 2)
  constexpr auto get(subrange<I, S, K>&& r);

效果:相当于:

if constexpr (N == 0)
  return r.begin(); 
else
  return r.end();

ranges::subrange::begin() 有两个重载:

constexpr I begin() const requires copyable<I>;
[[nodiscard]] constexpr I begin() requires (!copyable<I>);

我注意到这个std::get只有两个重载,并且非常量左值引用没有对应的重载,这使得我们无法将std::get应用于左值@987654336 @ 与非copyable 迭代器(godbolt)

#include <ranges>
#include <sstream>

int main() {
  auto ints = std::istringstream{"42"};
  auto is = std::ranges::istream_view<int>(ints);
  std::ranges::input_range auto r = std::ranges::subrange(is);
  auto b  = r.begin();      // OK
  auto b2 = std::get<0>(r); // Error, passing 'const subrange' as 'this' argument discards qualifiers
}

那么为什么std::get 对于ranges::subrange 只有两个函数重载?它会错过ranges::subrange&amp;const ranges::subrange&amp;&amp; 的重载吗?这是标准缺陷还是故意的?

【问题讨论】:

    标签: c++ c++20 std-ranges


    【解决方案1】:

    作为一般规则,定义良好的代码中的完整格式subrange 表示有效范围,如果它存储大小,则大小等于范围的大小。这反映在每个非默认构造函数的前提条件中(默认构造状态仍然可以部分形成)。由于引入了仅移动迭代器(因为非常量 begin 需要将迭代器移出),这有点混乱,但仍然是设计意图。

    换句话说,subrangepairtuplearray 完全不同。这三个是没有语义的值的聚合,它们的get 重载通过透明地传播 cv-qualification 和值类别来反映这一点。另一方面,subrange 确实具有语义——它不仅仅是一对迭代器和哨兵。它的get 只用于阅读,从不用于写作。这就是为什么 get 上的 subrange 按值返回的原因。

    提供非常量左值get 重载没有多大意义;通过可变引用返回是不可能的;通过引用返回 const 不同于其他一切(也令人惊讶)。按值返回意味着在唯一的情况下它会有所不同,左值 subrange 上的 get 是破坏性操作,这是非常出乎意料的。

    【讨论】:

    • 另一个问题是,我们是否应该对第一个重载进行额外的约束,以消除函数体内发生的“discarded const qualifier”错误?我打算为它提交一个LWG,但我不知道是否值得。
    • 我认为没有理由禁止 get&lt;1&gt;.end() 更多。它完全无害,可能很有用。不过,我可以在检查 begin 是否可以在约束中调用时看到一些价值。
    猜你喜欢
    • 2016-11-15
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多