![](/img/trans.png)
[英]What is/was the purpose of std::make_array? Is it still needed in C++20?
[英]What is the purpose of C++20 std::common_reference?
common_reference
来自我努力提出 STL 迭代器的概念化,以适应代理迭代器。
在 STL 中,迭代器有两种特别感兴趣的关联类型: reference
和value_type
。 前者是迭代器的operator*
的返回类型,而value_type
是序列元素的(非常量,非引用)类型。
通用算法通常需要做这样的事情:
value_type tmp = *it;
...所以我们知道这两种类型之间一定存在某种关系。 对于非代理迭代器,关系很简单: reference
始终是value_type
,可选 const 和引用限定。 定义InputIterator
概念的早期尝试要求表达式*it
可转换为const value_type &
,并且对于大多数有趣的迭代器来说就足够了。
我希望 C++20 中的迭代器比这更强大。 例如,考虑一个zip_iterator
的需求,它在锁步中迭代两个序列。 当您取消引用zip_iterator
,您将获得两个迭代器reference
类型的临时pair
。 因此, zip
vector<int>
和vector<double>
将具有以下关联类型:
zip
迭代器的reference
: pair<int &, double &>
zip
迭代器的value_type
: pair<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
}
CR
是通用参考。 所有算法都可以依赖于这种类型存在的事实,并且可以使用std::common_reference
来计算它。
所以,这就是common_reference
在 C++20 的 STL 中扮演的角色。 通常,除非您正在编写通用算法或代理迭代器,否则您可以放心地忽略它。 它在幕后确保您的迭代器履行其合同义务。
编辑:OP 还要求举个例子。 这有点做作,但想象一下它是 C++20,并且您得到一个R
类型的随机访问范围r
,您对此一无所知,并且您想sort
范围进行sort
。
进一步想象一下,出于某种原因,您想要使用单态比较函数,例如std::less<T>
。 (也许你型擦除的范围,你也需要键入擦除的比较功能,并使其通过一个virtual
?同样,舒展。)应该什么T
是std::less<T>
为此,您将使用common_reference
或根据它实现的助手iter_common_reference_t
。
using CR = std::iter_common_reference_t<std::ranges::iterator_t<R>>;
std::ranges::sort(r, std::less<CR>{});
即使范围r
有代理迭代器,这也保证有效。
我还没有在任何可以访问的编译器中看到它,但是它只是用于引用的std::common_type
。 它允许您编写函数,例如使用公共基类作为返回类型,而与实例化期间的参数顺序无关。 这是一个使用-std=c++2a
的std::common_type
与clang11和gcc9一起使用的示例:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template <typename T1, typename T2>
inline typename std::common_type<T1, T2>::type& some_call(int n, T1& t1, T2& t2) {
return n ? t1 : t2;
}
class A {
public:
virtual ~A() {}
virtual void say_hi() {
std::cerr << "Hi from A!" << std::endl;
}
};
class B : public A {
public:
virtual void say_hi() {
std::cerr << "Hi from B!" << std::endl;
}
};
int main() {
A a{}; B b{};
some_call(0, a, b).say_hi();
some_call(1, a, b).say_hi();
some_call(0, b, a).say_hi();
some_call(1, b, a).say_hi();
return 0;
}
结果是模板总是A&
推断为返回类型,并将正确调用虚拟函数say_hi
。
但是,您可以看到,返回类型中的寂寞&
被淹没了,所以我确定主要动机是std::common_reference<T1, T2>::type
提供的可读性超过std::common_type<T1, T2>::type&
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.