c++ - 为什么 std::get 只有 range::subrange 的两个函数重载?

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

标准中有四种pair-like类型,即std::array , std::pair , std::tuple , 和 ranges::subrange ,其中std::get的过载为 ranges::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);

Effects: Equivalent to:

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到左值 input_range与非 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& 的重载和 const ranges::subrange&& ?这是标准缺陷还是有意为之?

最佳答案

作为一般规则,一个完整的 subrange在定义良好的代码中代表一个有效的范围,如果它存储了一个大小,那么这个大小就等于该范围的大小。这反射(reflect)在每个非默认构造函数的前提条件中(默认构造状态仍然可以是部分形成的)。由于引入了仅移动迭代器(因为非常量 begin 需要将迭代器移出),这有点困惑,但仍然是设计意图。
换句话说,subrange很不一样pair , tuple , 或 array .这三个是没有语义的值的聚合,它们的 get重载通过透明地传播 cv 限定和值类别来反射(reflect)这一点。 subrange ,另一方面,确实有语义——它不仅仅是一对迭代器和哨兵。它的 get只为阅读,绝不为写作。这就是为什么getsubrange按值返回。
提供非常量左值没有多大意义get重载;通过可变引用返回是不可能的;通过引用返回 const 不同于其他一切(也令人惊讶)。按值返回意味着在唯一的情况下它会有所不同,get在左值 subrange是一种破坏性的操作,这将是非常出乎意料的。

关于c++ - 为什么 std::get 只有 range::subrange 的两个函数重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69077753/

相关文章:

c++ - 将非 char* 参数传递给 execvp

c++ - 使用 Floyd-Warshall 查找所有最短路径和距离

c++ - NetBeans C++ 8.0.2 输出中这些消息的含义是什么?

c++ - 为什么没有引入std::ranges::?

c++ - 使用基于概念的递归函数模板在扣除 'auto [...] ' 之前使用 'auto'

c++ - WKT与GeoJson的区别(数据解析)

c++ - 为 c++20 编写输出迭代器

c++ - 可变函数重载和 SFINAE - 解决歧义以模拟 "hide by signature"

c++ - 为什么 C++ 函数参数包必须是占位符或包扩展?

c++ - 范围和临时初始化列表