C ++ 20 wprowadza std::common_reference
. Jaki jest jego cel? Czy ktoś może podać przykład jego użycia?
C ++ 20 wprowadza std::common_reference
. Jaki jest jego cel? Czy ktoś może podać przykład jego użycia?
Odpowiedzi:
common_reference
wyszedł z moich wysiłków, aby wymyślić koncepcję iteratorów STL, która obsługuje iteratory proxy.
W STL iteratory mają dwa powiązane typy szczególnego zainteresowania: reference
i value_type
. Pierwszy z nich to typ zwracany przez iterator operator*
, a value_type
jest to (nie stały, brak odniesienia) elementów sekwencji.
Ogólne algorytmy często muszą robić takie rzeczy:
value_type tmp = *it;
... więc wiemy, że musi istnieć pewien związek między tymi dwoma typami. W przypadku iteratorów innych niż proxy związek jest prosty: reference
jest zawsze value_type
, opcjonalnie const i referencja kwalifikowana. Wczesne próby zdefiniowania InputIterator
koncepcji wymagały *it
konwersji tego wyrażenia const value_type &
, a dla najbardziej interesujących iteratorów było to wystarczające.
Chciałem, aby iteratory w C ++ 20 były bardziej wydajne. Rozważmy na przykład potrzebę zip_iterator
iteracji dwóch sekwencji w kroku blokowania. Gdy odrzucisz a zip_iterator
, otrzymasz tymczasowy typ pair
dwóch iteratorów reference
. Więc, zip
ingvector<int>
i a vector<double>
miałyby następujące powiązane typy:
zip
iterator's reference
:pair<int &, double &>
zip
iterator's value_type
:pair<int, double>
Jak widać, te dwa typy nie są ze sobą powiązane po prostu poprzez dodanie najwyższej klasy kwalifikacji cv i ref. A jednak pozwolenie, by te dwa typy były dowolnie różne, wydaje się złe. Oczywiście jest kilka tutaj związek. Ale jaka jest relacja i co ogólne algorytmy działające na iteratorach mogą bezpiecznie założyć o tych dwóch typach?
Odpowiedź w C ++ 20 jest taka, że dla każdego poprawnego typu iteratora, proxy lub nie, typy reference &&
i value_type &
współużytkowane są wspólne odwołania . Innymi słowy, dla niektórych iteratorów it
istnieje jakiś typ, CR
który sprawia, że następujący poprawnie sformułowany:
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
jest wspólnym odniesieniem. Wszystkie algorytmy mogą polegać na fakcie, że ten typ istnieje i można z niego korzystaćstd::common_reference
do jego obliczenia.
Taką rolę common_reference
pełni STL w C ++ 20. Zasadniczo, chyba że piszesz ogólne algorytmy lub iteratory proxy, możesz go bezpiecznie zignorować. Jest pod osłonami, zapewniając, że Twoje iteratory wypełniają swoje zobowiązania umowne.
EDYCJA: PO poprosił również o przykład. Jest to trochę wymyślone, ale wyobraź sobie, że jest to C ++ 20, a otrzymasz zakres r
typu dostępu o swobodnym dostępie, R
o którym nic nie wiesz, i chcesz do sort
tego zakresu.
Ponadto wyobraź sobie, że z jakiegoś powodu chcesz użyć monomorficznej funkcji porównawczej, takiej jak std::less<T>
. (Może skasowałeś zakres i musisz także skasować funkcję porównania i przekazać ją przez virtual
? Ponownie, odcinek.) Co powinno T
być std::less<T>
? Do tego użyłbyś common_reference
lub pomocnika, iter_common_reference_t
który jest zaimplementowany pod tym względem.
using CR = std::iter_common_reference_t<std::ranges::iterator_t<R>>;
std::ranges::sort(r, std::less<CR>{});
Gwarantuje to, że zadziała, nawet jeśli zasięg r
ma iteratory proxy.
pair<T&,U&>
i pair<T,U>&
miałaby wspólny punkt odniesienia, a byłoby po prostu pair<T&,U&>
. Jednak std::pair
nie ma konwersji z pair<T,U>&
na, pair<T&,U&>
nawet jeśli taka konwersja jest w zasadzie rozsądna. (Nawiasem mówiąc, dlatego nie mamy zip
widoku w C ++ 20).
pair
zamiast typu, który mógłby być specjalnie zaprojektowany do jego celu , w razie potrzeby z odpowiednimi niejawnymi konwersjami?
std::pair
; zrobi to dowolny odpowiedni typ podobny do pary z odpowiednimi konwersjami, a zakres v3 definiuje taki typ podobny do pary. W Komitecie LEWG nie podobał się pomysł dodania do Biblioteki Standardowej typu, który był prawie, ale nie całkiem std::pair
, normatywny czy nie, bez uprzedniej staranności w kwestii zalet i wad zwykłego wykonywania std::pair
pracy.
tuple
, pair
, tomato
, to
- MAH
- to
. pair
ma tę fajną funkcję, dzięki której można uzyskać dostęp do elementów za pomocą .first
i .second
. Wiązania strukturalne pomagają w niektórych niezręcznościach pracy z tuple
s, ale nie ze wszystkimi.