2017-10-12 23 views
6

bir dizeden ardışık boşlukları kaldırmak için std::unique nasıl kullanılacağı hakkında cppreference bir örnek vardır benzersiz örnek: gereksinimleri bölümünde,std :: hiçbir denklik ilişkisi (ardışık boşlukları kaldırın)

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'; 

Ancak Eşsiz o, belirtilen ikili yüklemi s kullanarak karşılaştırılır. Eşdeğerlik ilişkisi değilse, davranışı tanımsızdır. Bu soru şu: geçerli örnek geçerli mi? Öngörücü açıkça yansıtıcı değildir (iki 'n' karakter eşitsizliği karşılaştırır) ve dolayısıyla bir denklik ilişkisi değildir.

+0

Bu bir denkliktir. Tüm boşluklar benzersizdir. – stark

+0

Bu kırılma ('a' a '), simetri doğru (' a ~ b <=> b ~ a ') – Jarod42

+0

@ Jarod42: Evet, ben sadece düzeltildi, yansıma – Andre

cevap

2

yüklem gerçekten özellikle refleksivite olarak, Equivalence_relation saygı değildir:

a ~ a 

olsa geçerli olabilir etmektedir, örneğin, ilk 'n' ikinci 'n' farklı olabilir. problemi, yanlış olan (boşluk karakteri hariç) kendi kendini karşılaştırma ile ilgilidir.

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

gerçeği kendisiyle karşılaştıran o algoritması için çoğunlukla yararsız olduğunu, bu yüzden UB burada en uygulanmasında nelerle yazar yapar: yüklemi düzeltmek için

bir yolu dikkate adresini almaktır.

Geçerli uygulama yüklemenin yeniden yansıma olup olmadığını kontrol edebilir ve yanlış bir şey yaparsa (UB olarak). Benzersiz

+0

Bu düzgün bir hiledir. (Herhangi bir sebep olmaksızın) yüklemenin, nesnenin belleğe gerçek kimliğine güvenmeden, eşdeğerin 'value_type'ını eşdeğerlikle karşılaştırması gerektiği varsayılırdı. Referans olarak iletebileceğiniz açıktır, ancak bu bilgiyi denklik ilişkisi için kullanmanıza izin verilemeyecek kadar açık değildir. – Andre

+1

Adresi almak daha iyi değil! Bir değeri kopyalamak sonucu değiştirmemesi gerekiyor, ör.'const char n = 'n'; pred (n, n)/* == doğru * /; const char n2 = n; pred (n, n2)/* == false * /; '' –

+0

@ArneVogel: Daha zor olduğunu söyleyebilirim, yüklem doğrudur (const char & 'için Equivalence gereksinimini karşıla), ancak verilen ile uyumludur yineleyici? * "Dereferanslı ForwardIt türünün [MoveAssignable] gereksinimlerini karşılaması gerekir (http://en.cppreference.com/w/cpp/concept/MoveAssignable)." *. refence MoveAssignable değil, "char" (ancak diğer yüklemeyi kullanarak). – Jarod42

0

: sadece bir boşluk olması örnek yüklemi için bir eleman tanımlarsak

"aralığından eşdeğer elemanlar her ardışık gruptan birinci eleman ama ortadan kaldırır", tüm doğrudur. Eşdeğerlik sadece boşluklara uygulanmalıdır. 'n' bir yer değil, bu yüzden bir yüklem, yanlış döndürür.