繁体   English   中英

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

[英]What is the purpose of C++20 std::common_reference?

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

common_reference来自我努力提出 STL 迭代器的概念化,以适应代理迭代器。

在 STL 中,迭代器有两种特别感兴趣的关联类型: referencevalue_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迭代器的referencepair<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 ?同样,舒展。)应该什么Tstd::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++2astd::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.

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