C ++ 20 вводит std::common_reference
. Какова его цель? Может кто-нибудь привести пример его использования?
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
итерации двух последовательностей в шаге блокировки. Когда вы разыменовываете a zip_iterator
, вы получаете временный тип pair
двух итераторов reference
. Таким образом, 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
играет STL в C ++ 20. Как правило, если вы не пишете универсальные алгоритмы или прокси-итераторы, вы можете спокойно их игнорировать. Он находится под прикрытием, гарантируя, что ваши итераторы выполняют свои договорные обязательства.
РЕДАКТИРОВАТЬ: ОП также попросил пример. Это немного надумано, но представьте, что это C ++ 20, и вам дан диапазон произвольного доступа r
типа, R
о котором вы ничего не знаете, и вы хотите получить 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
есть прокси-итераторы.
pair<T&,U&>
иpair<T,U>&
будет иметь общую ссылку, и это будет простоpair<T&,U&>
. Однако, потомуstd::pair
что нет преобразования изpair<T,U>&
в,pair<T&,U&>
хотя такое преобразование в принципе звучит. (Это, кстати, поэтому у нас нетzip
представления в C ++ 20.)pair
вместо типа, специально разработанного для этой цели? с соответствующими неявными преобразованиями по мере необходимости?std::pair
; подойдет любой подходящий парный тип с соответствующими преобразованиями, а range-v3 определяет такой парный тип. В Комитете LEWG не понравилась идея добавить в Стандартную библиотеку тип, который был бы почти, но не совсемstd::pair
, будь то нормативным или нет, без предварительного тщательного изучения плюсов и минусов простого выполненияstd::pair
работы.tuple
,pair
-tomato
,to
-MAH
-to
.pair
имеет эту приятную особенность, что вы можете получить доступ к элементам с помощью.first
и.second
. Структурированные привязки помогают с некоторыми неудобствами работы сtuple
s, но не со всеми.