Neden “b <a? a: b yerine “a <b? b: a ”max şablonu uygulamak için?


154

C ++ Şablonlar - Komple Kılavuzu, 2nd Edition tanıtır max şablonu:

template<typename T>
T max (T a, T b)
{
  // if b < a then yield a else yield b
  return  b < a ? a : b;
}

Ve bunun “b < a ? a : b”yerine kullanmayı açıklar “a < b ? b : a”:

[StepanovNotes] 'a göre max () şablonunun bilerek “b <a? a: b yerine “a <b? b: a ”işlevini, iki değer eşdeğer olsa da eşit olmasa bile düzgün çalıştığından emin olmak için.

" even if the two values are equivalent but not equal." Nasıl anlaşılır ? “a < b ? b : a”benim için aynı sonuca sahip gibi görünüyor.


8
Bana yanlış görünüyor ... Hem cevaplar "doğru", ama eğer ave bolan eşdeğer , o zaman !(a < b) && !(b < a)doğrudur, bu yüzden a < bve b < aher ikisi de yanlış, bu yüzden de b < a ? a : b, bsen istiyorsun ... istediğini olmadığı, döndürülür a < b ? b : a.
Holt

1
Sık sık eşdeğer ayırt edebilir ave bbirlikte std::addressofet. ark.
Caleth

14
Yaparsanız a = max(a, b);(tekrar tekrar) agereksiz yere değiştirmek istemeyebilirsiniz .
Bo Persson

2
BTW bu şablon, const-reference ile parametreleri almalı ve const-reference ile döndürmelidir, aksi takdirde, bir sürü yararsız kopya yapıyorsunuz (ve abir kopyasıyla geçersiz kılacaksınız a).
Holt

3
@Caleth: Hem denkliği hem de eşitliği olan standart tip CaseInsensitiveString'dir. Bu tip için ne <A ne de A <a. Ama std::addressofilgisiz. Aslında, verilen T max(T a, T b)için zaten biliyoruz addressof(a) != addressof(b).
MSalters

Yanıtlar:


150

std::max(a, b)aslında aikisi eşdeğer olduğunda geri dönmesi belirtilir .

Yani bir hata olarak kabul edilir Stepanov o verilen bu faydalı özelliği kırar çünkü ve diğerleri ave bher zaman sıralama bunları birlikte, olabilir {min(a, b), max(a, b)}; bunun için , argümanlar eşdeğer olduğunda max(a, b)geri dönmek istersiniz b.


48
Bu bağlantıdan "Bunu yapan insanları suçlamak benim için zor: sonuçta, onlar sadece benim yazdığım max C ++ standart şartnamesine uyuyorlar. Yanıldığımı görmek birkaç yılımı aldı." - vay!
Jack Aidley

23
sadece yapamaz {min(a, b), max(b, a)}mısın
Kaptan Adam

12
@CaptainMan: Evet, ama yine de daha az açık. Ben max(a,b)bir-ve-sadece-eğer min(a,b)b döndürürse mantıklı bir anlam ifade eder ve tersi böylece birbirinin tersi ve (sıralanmamış) kümesinin {min(a,b), max(a,b)}her zaman eşit olması gerektiğini savunuyorum {a,b}.
Jack Aidley

5
@ jpmc26: Örneğin olayların bir listesini zamana göre sıralıyorsanız, sıralama işleminin girdide tam olarak bir kez görünen her olayın olmasını sağlamak için kararlı olup olmadığına dikkat etmek gerekmez, aynı şekilde çıktıda tam olarak bir kez görünür. Bazı işlemler (yinelenen olayları bulma ve ortadan kaldırma gibi) tam bir sipariş kullanmayı gerektirebilir, ancak diğer birçok durumda, eşzamanlı olayları keyfi sırada listelemek kabul edilebilir, ancak bunları çoğaltmak veya atlamak değil.
supercat

2
Uygulama @supercat minve maxbir şey ama zaman damgası bu senaryoda (sıralama anahtarı) hiçbir mantıklı. Eğer eşitlik birbirinin yerine geçebilirlik anlamına gelmiyorsa, olayların (nesnelerin) kendileri bile karşılaştırılmamalıdır. Tek yol {min(a, b), max(a, b)}yapar herhangi nesneler birbirinin ise bir çeşit mekanizmadır olarak mantıklı.
jpmc26

62

Bu yanıt, verilen kodun neden C ++ standart bakış açısından yanlış olduğunu açıklar, ancak bağlam dışıdır.

Bağlamsal bir açıklama için @ TC'nin cevabına bakınız .


Standart std::max(a, b)şu şekilde tanımlanır [alg.min.max] (vurgu benimdir):

template<class T> constexpr const T& max(const T& a, const T& b);

Gerektiriyor : T Tipi LessThanComparable (Tablo 18).

Döndürür : Daha büyük değer.

Açıklamalar : Bağımsız değişkenler eşdeğer olduğunda ilk bağımsız değişkeni döndürür.

Burada Eşdeğer araçlarının !(a < b) && !(b < a)edilir true [7. alg.sorting] .

Özel olarak, ave beşdeğer, her ikisi de a < bve b < avardır falsesağında değeri bu nedenle, :bu yüzden, koşullu operatör döndürülme aböylece sağ olmak zorundadır:

a < b ? b : a

... doğru cevap gibi görünüyor. Bu, libstdc ++ ve libc ++ tarafından kullanılan sürümdür .

Dolayısıyla, teklifinizdeki bilgiler mevcut standarda göre yanlış görünüyor, ancak tanımlandığı bağlam farklı olabilir.


4
Sorunu açıklayan Godbolt bağlantısı (tanımı için son @songyuanyao X).
Holt

1
@JackAidley Akıl yürütmenin mevcut standardı hedeflediğini belirtmek için cevabı düzenledim.
Holt

@codekaizer Aslında "equiv (a, b) 'yi! comp (a, b) &&! comp (b, a) olarak tanımlarsak" derim . Daha iyi bir teklif (standart 3 satır aşağıda ...) bağlantısını değiştirdim.
Holt

1
Hayrete kimse kayan nokta, söz etmiştir a<bve b<aonlar ediyoruz sırasız (biri veya her ikisi NaN, bu yüzden çünkü hem yanlış olabilir ==çok yanlıştır). Bu bir çeşit denklik olarak görülebilir. gevşekçe ilgili: x86'nın maxsd a, btalimatı uygular a = max(b,a) = b < a ? a : b. ( X86'da dalsız FP min ve maks veren talimat nedir? ). Talimat, kaynak işleneni (2'nci) sıralanmamış olarak tutar, bu nedenle bir dizi üzerindeki bir döngü, herhangi bir NaN varsa size NaN verir. Ancak max_seen = max(max_seen, a[i])NaN'leri görmezden gelecek.
Peter Cordes


21

Mesele, eşdeğer olduğunda hangisinin döndürüleceğidir; bu dava için (yani ilk argüman) std::maxgeri dönmek zorundadır a.

Eğer eşdeğerlerse, geri döner a.

Bu yüzden a < b ? b : akullanılmalıdır; Öte yandan, yanlış b < a ? a : b;dönecektir b.

(@Holt'un dediği gibi, teklif tam tersi görünüyor.)

"iki değer eşdeğerdir ancak eşit değildir", karşılaştırıldıklarında aynı değere sahip oldukları anlamına gelir, ancak diğer bazı yönlerde farklı nesnelerdir.

Örneğin

struct X { int a; int b; };
bool operator< (X lhs, X rhs) { return lhs.a < rhs.a; }
X x1 {0, 1};
X x2 {0, 2};
auto x3 = std::max(x1, x2); // it's guaranteed that an X which cantains {0, 1} is returned

1
Eşdeğer ve neden eşdeğer ise , neden std::max(a, b)geri dönmesi gerektiğine ilişkin ayrıntılar verebilir misiniz? aab
ク り ネ ロ ク

4
@ ネ ロ ク - Standardın sadece keyfi bir seçimi . İyi bir şey olsa biraz tartışmalı olsa da.
StoryTeller - Unlander Monica

Sadece ben miyim yoksa bu soru ile çelişiyor mu? Eğer ave beşdeğer, o zaman !(a < b) && !(b < a)doğrudur, bu yüzden a < bve b < a... yani, yanlış mı?
Holt

2
@ ネ ロ ク Sanırım standart sadece onu belirlemek istiyor; eşdeğer olduklarında hangisi iade edilmelidir.
songyuanyao

1
bir nesnenin neden "eşdeğer" olduğu, ancak "eşit" olmadığı konusunda hafızamı yenilediğiniz için teşekkürler
Jeff Walker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.