2017-10-12 11 views
6

Jest przykładem na cppreference jak używać std::unique usunąć kolejne spacje z łańcucha:std :: unikalny przykład bez relacji równoważności (usunięcie kolejnych spacji)

std::string s = "wanna go to  space?"; 
auto end = std::unique(s.begin(), s.end(), [](char l, char r){ 
    return std::isspace(l) && std::isspace(r) && l == r; 
}); 
// s now holds "wanna go to space?xxxxxxxx", where 'x' is indeterminate 
std::cout << std::string(s.begin(), end) << '\n'; 

Jednak w sekcji Wymagania dla unikalny to stany

Elementy są porównywane przy użyciu podanego predykatu binarnego p. Zachowanie jest niezdefiniowane, jeśli nie jest relacją równoważności.

Moje pytanie brzmi: czy podany przykład jest ważny? Predykat wyraźnie nie jest refleksyjny (dwa znaki "n" są nierównomierne), a zatem nie jest równoważny.

+0

Jest to równoważność. Wszystkie nie-spacje są unikalne. – stark

+0

To jest refleksyjność, która jest zepsuta ("a ~ a"), symetria jest poprawna ('a ~ b <=> b ~ a') – Jarod42

+0

@ Jarod42: Tak, właśnie to poprawiłem, miałem na myśli refleksyjną – Andre

Odpowiedz

2

Predykat rzeczywiście nie przestrzega Equivalence_relation, w szczególności zwrotności:

a ~ a 

Przykład wskazaniu może być ważne, choć najpierw 'n' może być inny niż drugi 'n'. Problem polega na tym, że samo porównanie jest fałszywe (z wyjątkiem znaku spacji).

Jednym ze sposobów, aby rozwiązać ten predykat jest podjęcie adres pod uwagę:

[](const char& l, const char& r) 
{ 
    return (&l == &r) 
     || (l == r && std::is_space(l)); 
} 

Faktem jest, że w porównaniu z samym sobą jest przeważnie bezużyteczny dla tego algorytmu, więc UB tutaj robi to, co autor oczekiwać w większości implementacji.

Prawidłowe wdrożenie może sprawdzić zwrotność predykatu, a jeśli coś źle zrobi (jako UB).

+0

To czysta sztuczka. Założę się (bez żadnego konkretnego powodu), że predykat ma porównać iteracyjny "value_type" dla równoważności, bez polegania na rzeczywistej tożsamości obiektów w pamięci. Oczywiste jest, że możesz przekazać przez referencję, ale nie jest to tak oczywiste, że możesz używać tych informacji do relacji równoważności. – Andre

+1

Podanie adresu nie jest lepsze! Kopiowanie wartości nie powinno zmieniać wyniku, np.'' const char n = 'n'; pred (n, n)/* == true * /; const char n2 = n; pred (n, n2)/* == false * /; '' –

+0

@ArneVogel: Powiedziałbym, że jest bardziej skomplikowany, predykat jest poprawny (spełnij wymagania równoważności dla 'const char &'), ale czy jest zgodny z podanym iterator? * "Typ dereferencji ForwardIt musi spełniać wymagania [MoveAssignable] (http://en.cppreference.com/w/cpp/concept/MoveAssignable)." *. refence nie są MoveAssignable, 'char' jest (ale używa innego predykatu). – Jarod42

0

wyjątkowy: „Eliminuje wszystkie oprócz pierwszego elementu z każdej kolejnej grupy równoważnych elementów z zakresu”

Jeśli zdefiniować element dla orzecznika próbki być tylko przestrzeń, to wszystko jest prawidłowe. Równoważność powinna być stosowana tylko do przestrzeni. 'n' nie jest spacją, więc predykat zwraca fałsz.

Powiązane problemy