[英]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.