C ++ 20 std :: common_reference的目的是什么?

康桓瑋*_*康桓瑋 26 c++ metaprogramming type-traits c++20

C ++ 20引入std::common_reference。目的是什么?有人可以举一个使用它的例子吗?

Eri*_*ler 24

common_reference 从我的努力出发,提出了可容纳代理迭代器的STL迭代器的概念化。

在STL中,迭代器具有两种相关的特殊类型:referencevalue_type。前者是迭代器的返回类型operator*,而value_typeis是序列元素的(非常量,非引用)类型。

通用算法通常需要执行以下操作:

value_type tmp = *it;
Run Code Online (Sandbox Code Playgroud)

...所以我们知道这两种类型之间一定存在某种关系。对于非代理迭代器,关系很简单:reference始终为value_type,可选为const和引用限定。早期定义该InputIterator概念的尝试要求该表达式*it可转换为const value_type &,并且对于大多数有趣的迭代器而言已足够。

我希望C ++ 20中的迭代器比这更强大。例如,考虑zip_iterator在锁步中迭代两个序列的a的需求。取消引用a时zip_iterator,将获得pair两个迭代器reference类型的临时类型。因此,zip'ing a vector<int>和a vector<double>将具有以下关联类型:

zip迭代器的referencepair<int &, double &>
zip迭代器的value_typepair<int, double>

如您所见,仅通过添加顶级cv-和ref限定条件,这两种类型就不会相互关联。但是,让两种类型任意不同会让人感到错误。显然这里有一些关系。但是两者之间的关系是什么,在迭代器上运行的通用算法可以安全地假设这两种类型呢?

在C ++ 20中的答案是,对于任何有效的迭代器类型,代理与否,其种类reference &&value_type &共享一个共同的参考。换句话说,对于某些迭代器,it有某种类型CR可以使以下格式正确:

void foo(CR) // CR is the common reference for iterator I
{}

void algo( I it, iter_value_t<I> val )
{
  foo(val); // OK, lvalue to value_type convertible to CR
  foo(*it); // OK, reference convertible to CR
}
Run Code Online (Sandbox Code Playgroud)

CR是通用参考。所有算法都可以依赖这种类型存在的事实,并可以std::common_reference用来计算它。

因此,这就是common_referenceC ++ 20中STL中扮演的角色。通常,除非您正在编写通用算法或代理迭代器,否则可以放心地忽略它。它可以确保您的迭代器履行其合同义务。

  • @EricNiebler:“ *顺便说一句,这就是为什么我们在C ++ 20中没有zip视图。*”是否有某些原因导致zip迭代器必须使用“ pair”而不是可能是专为其目的而设计,并根据需要进行适当的隐式转换? (3认同)
  • @Nicol Bolas不需要使用`std :: pair`;。任何具有适当转换的适当成对类型都可以,并且range-v3定义了这种成对类型。在委员会上,LEWG不喜欢在标准库中添加几乎但不是很标准的std :: pair类型的想法,无论它是否具有规范性,而不必先对简单的优缺点进行尽职调查使`std :: pair`工作。 (3认同)
  • 也许我很笨,但是你能澄清一下 zip-pair 示例中的共同参考是什么吗? (2认同)
  • 理想情况下,“ pair &lt;T&,U&&gt;”和“ pair &lt;T,U&gt;&`”应具有共同的引用,而只是“ pair &lt;T&,U&&gt;”。但是,对于“ std :: pair”,即使从原则上讲是这样的转换,也没有从“ pair &lt;T,U&gt;&”到“ pair &lt;T&,U&&gt;”的转换。(顺便说一下,这就是为什么我们在C ++ 20中没有`zip`视图。) (2认同)
  • `元组`,`对`,`蕃茄`,`到`-`MAH`-`到`。对具有这个很好的功能,您可以使用.first和.second访问元素。结构化绑定有助于解决使用tuple的一些尴尬,但不是全部。 (2认同)