Яка мета C ++ 20 std :: common_reference?


Відповіді:


46

common_reference Я вийшов із моїх зусиль, щоб придумати концептуалізацію ітераторів STL, що вміщує проксі-ітераторів.

У STL у ітераторів є два асоційовані типи, що представляють особливий інтерес: referenceта value_type. Перший - це тип повернення ітератора operator*, а тип value_type(не-const, нереференційний) елементів послідовності.

У загальних алгоритмах часто виникає потреба робити такі дії:

value_type tmp = *it;

... тому ми знаємо, що між цими двома типами має бути певний зв’язок. Для непроксі-ітераторів зв’язок простий: referenceзавжди value_type, необов'язково const та посилання кваліфіковано. Ранні спроби визначення InputIteratorпоняття вимагали, щоб вираз *itбув конвертованим const value_type &, а для найбільш цікавих ітераторів достатньо.

Я хотів, щоб ітератори в C ++ 20 були потужнішими за це. Наприклад, розглянемо потреби того, zip_iteratorщо ітераціює дві послідовності в режимі блокування. При відпуску a zip_iteratorви отримуєте тимчасовий pairз двох referenceтипів ітераторів . Отже, zip'a vector<int>і a 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. Як правило, якщо ви не пишете загальні алгоритми чи проксі-ітератори, ви можете їх ігнорувати. Він знаходиться під обкладинкою, яка гарантує, що ваші ітератори виконують свої договірні зобов’язання.


EDIT: ОП також попросила прикладу. Це трохи надумано, але уявіть, що це 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має проксі-ітератори.


2
Можливо, я щільний, але чи можете ви уточнити, що є загальним посиланням у прикладі zip-pair?
happydave

4
В ідеалі pair<T&,U&>і pair<T,U>&було б спільне посилання, і було б просто pair<T&,U&>. Однак, для std::pairцього не існує перетворення pair<T,U>&на, pair<T&,U&>навіть якщо таке перетворення є принциповим. (Це, до речі, тому ми не маємо zipвиду в C ++ 20.)
Ерік Ніблер,

4
@EricNiebler: " Це, до речі, тому ми не маємо перегляд поштового індексу в C ++ 20. " Чи є якась причина, чому повинен був використовувати ітератор zip pairзамість типу, який може бути спеціально розроблений для його призначення з відповідними неявними конверсіями, якщо це потрібно?
Нікол

5
@Nicol Bolas Не потрібно використовувати std::pair; будь-який відповідний тип, подібний до пари, з відповідними перетвореннями буде робити, а range-v3 визначає такий тип, що нагадує пару. Щодо Комітету, ЛЕВГ не сподобалась ідея додавати до Стандартної бібліотеки тип, який був майже, але не зовсім std::pair, будь то нормативний чи ні, не попередньо старанно ставлячись до плюсів і мінусів просто зробити std::pairроботу.
Ерік Ніблер

3
tuple, pair, tomato, to- MAH- to. pairмає цю приємну особливість, що ви можете отримати доступ до елементів за допомогою .firstта .second. Структуровані прив’язки допомагають дещо незручно працювати з tuples, але не всіма.
Ерік Ніблер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.