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_typejest 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: referencejest zawsze value_type, opcjonalnie const i referencja kwalifikowana. Wczesne próby zdefiniowania InputIteratorkoncepcji wymagały *itkonwersji 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_iteratoriteracji dwóch sekwencji w kroku blokowania. Gdy odrzucisz a zip_iterator, otrzymasz tymczasowy typ pairdwóch iteratorów reference. Więc, zipingvector<int> i a vector<double>miałyby następujące powiązane typy:
zipiterator'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 itistnieje jakiś typ, CRktó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
}
CRjest 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_referencepeł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 rtypu dostępu o swobodnym dostępie, Ro którym nic nie wiesz, i chcesz do sorttego 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 Tbyć std::less<T>? Do tego użyłbyś common_referencelub pomocnika, iter_common_reference_tktó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 rma 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::pairnie 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 zipwidoku w C ++ 20).
pairzamiast 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::pairpracy.
tuple, pair, tomato, to- MAH- to. pairma tę fajną funkcję, dzięki której można uzyskać dostęp do elementów za pomocą .firsti .second. Wiązania strukturalne pomagają w niektórych niezręcznościach pracy z tuples, ale nie ze wszystkimi.