2016-01-05 7 views
13

W latest paper on concepts N3701, jest następujący przykład z algorytmu sort:Dlaczego koncepcja Sortable wymaga całkowicie uporządkowanego typu wartości, podczas gdy std :: sort wymaga tylko "mniej niż" porównywalnego?

template<typename Cont> 
    requires Sortable<Cont>() 
void sort(Cont& cont) 

gdzie Sortable koncepcja jest zdefiniowana jako

template<typename T> 
concept bool Sortable() 
{ 
    return Permutable_container<T>() && Totally_ordered<Value_type<T>>(); 
} 

gdzie Totally_ordered, nie jest zaskoczeniem, jest zdefiniowany jako

template<typename T> 
constexpr bool Totally_ordered() 
{ 
    return Weakly_ordered<T>() && Equality_comparable<T>(); 
} 

, a z kolei Equality_comparable jest zdefiniowana jako

template<typename T> 
constexpr bool Equality_comparable() 
{ 
    return requires(T a, T b) { 
    {a == b} -> bool; 
    {a != b} -> bool; 
    }; 
} 

nie znalazłem definicji Weakly_ordered, ale wierzę, że powinno to wyglądać tak (mam rację?)

template<typename T> 
constexpr bool Weakly_ordered() 
{ 
    return requires(T a, T b) { 
    {a < b} -> bool; 
    {a <= b} -> bool; 
    {a > b} -> bool; 
    {a >= b} -> bool; 
    }; 
} 

dolnej linii, w tej definicji, jeśli chcę uporządkować std::vector<T>, muszę T dostarczenie wszystkie porównanie operatorów <, <=, >, >=, ==, !=. Jednak w ciągu całego życia C++, std::sort wymagany jest tylko operator <! Oto co mówi o std::sortcppreference:

Sortuje elementy w przedziale [pierwsza, ostatnia) w porządku rosnącym. Nie można zagwarantować, że kolejność równych elementów zostanie zachowana. Pierwsza wersja wersja używa operatora < do porównania elementów, druga wersja wykorzystuje podaną funkcję porównania comp obiektu.

Więc co, to znaczy, że w przyszłości C++ z koncepcjami, na v typu std::vector<T> gdzie T przewiduje jedynie operator<, std::sort(v.begin(), v.end()) zostanie skompilowany, a std::sort(v) nie będzie? Brzmi to szalenie.

Sprawdziłem to w bieżącym ranges-v3 implementation przez Eric Niebler, i działa tak, jak opisałem. Kod nie jest kompilowany, chyba że dostarczono wszystkich operatorów.

Zobacz również związany dyskusji: https://github.com/ericniebler/range-v3/issues/271

Odpowiedz

11

pojęć TS nie konceptualizacji biblioteki standardowej. To był tylko przykład; nic więcej.

Wersja Ranges TS sort wymaga Sortable, która domyślnie jest porównywana z klasą porównywania z std::less<>. Jednak wydaje się, że std::less<>::operator() nakłada wymóg TotallyOrdered na typy jego parametrów. Więc skąd pochodzi. Jest to uwaga o tym w P0021R0 (PDF):

[Od redakcji: Usuń stół [lessthancomparable] w [utility.arg.requirements].Zamień użycie LessThanComparable na TotallyOrdered (potwierdzając, że jest to zmiana powodująca złamanie, która sprawia, że ​​wymagania dotyczące typów są bardziej rygorystyczne). Zamień odniesienia na [lessthancomparable] z odniesieniami do [concepts.lib.compare.totallyally]]

Podkreślenie dodane. Ogólne problemy związane z tym appear to be on-hold, w oczekiwaniu na inne funkcje językowe (np. Niejawne utworzenie wszystkich innych operatorów opartych wyłącznie na operator< lub somesuch).

Można po prostu użyć wersji (porównawczej) funkcji porównania. Lub możesz po prostu użyć wersji iteratora std::sort, która nie będzie używać żadnych pojęć.


Należy również zauważyć, że z the introduction z the "spaceship operator" w C++ 20 (najwcześniej mogliśmy zobaczyć zakresach TS zintegrowane w standardzie), cała ta dyskusja staje się bezprzedmiotowa skutecznie. Prosta deklaracja auto operator<=>(const MyType &) = default; w klasie i nagle twój typ jest całkowicie uporządkowany.

+0

Sprawdziłem to w obecnej implementacji range-v3 przez Erica Nieblera (https://github.com/ericniebler/range-v3) i działa tak, jak to opisałem. Kod nie jest kompilowany, chyba że dostarczono wszystkich operatorów. Ta implementacja wymaga jednak 'IndirectCallableRelation'. – Mikhail

+0

@Mikhail: Czytałem dalej w specyfikacji. –

+0

Dziękuję. Zobacz także https://github.com/ericniebler/range-v3/issues/271 – Mikhail

Powiązane problemy