Tại sao nên sử dụng dịch vụ b <a? a: bv thay vì thế a <b? b: một người dùng để thực hiện mẫu tối đa?


154

Mẫu C ++ - Hướng dẫn hoàn chỉnh, Phiên bản 2 giới thiệu mẫu tối đa :

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

Và nó giải thích bằng cách sử dụng “b < a ? a : b”thay vì “a < b ? b : a”:

Lưu ý rằng mẫu max () theo [StepanovNotes] cố ý trả về bản b <a? a: bv thay vì thế a <b? b: một giá trị để đảm bảo rằng hàm hoạt động chính xác ngay cả khi hai giá trị tương đương nhưng không bằng nhau.

Làm sao để hiểu " even if the two values are equivalent but not equal."? “a < b ? b : a”dường như có kết quả tương tự với tôi


8
Vẻ không đúng với tôi ... Cả hai câu trả lời là "đúng", nhưng nếu abtương đương , sau đó !(a < b) && !(b < a)là sự thật, vì vậy a < bb < acả hai đều sai, vì vậy trong b < a ? a : b, bđược trả lại, mà không phải là những gì bạn muốn ... Bạn muốn a < b ? b : a.
Holt

1
Bạn thường có thể phân biệt giữa tương đương abvới std::addressofet. al.
Caleth

14
Nếu bạn làm a = max(a, b);(lặp đi lặp lại), bạn có thể không muốn thay thế một cách akhông cần thiết.
Bo Persson

2
BTW mẫu này sẽ lấy tham số bằng tham chiếu const và trả về chúng bằng tham chiếu const, nếu không, bạn đang thực hiện một loạt các bản sao vô dụng (và bạn sẽ ghi đè abằng một bản sao a).
Holt

3
@Caleth: Loại chính tắc có cả tương đương và bình đẳng là CaseInsensitiveString. Đối với loại đó, không phải là <A hay A <a. Nhưng std::addressoflà không liên quan. Trong thực tế, cho đã cho T max(T a, T b)chúng ta đã biết addressof(a) != addressof(b).
MSalters

Câu trả lời:


150

std::max(a, b)thực sự được chỉ định để trở lại akhi hai là tương đương.

Điều đó được coi là một sai lầm của Stepanov và những người khác vì nó phá vỡ tài sản hữu ích đã cho ab, bạn luôn có thể sắp xếp chúng theo {min(a, b), max(a, b)}; cho điều đó, bạn muốn max(a, b)quay lại bkhi các đối số tương đương.


48
Từ liên kết đó "Thật khó để tôi đổ lỗi cho những người làm như vậy: sau tất cả, họ chỉ tuân theo đặc tả tiêu chuẩn C ++ của max được viết bởi tôi. Tôi mất vài năm để thấy rằng tôi đã nhầm." - wow!
Jack Aidley

23
bạn không thể làm gì {min(a, b), max(b, a)}?
Thuyền trưởng Man

12
@CaptainMan: Có, nhưng nó vẫn chưa rõ ràng. Tôi sẽ lập luận rằng nó có ý nghĩa logic max(a,b)sẽ trả về một giá trị if-and-only-if min(a,b)trả về b và ngược lại sao cho chúng ngược lại với nhau và tập hợp (không có thứ tự) {min(a,b), max(a,b)}luôn bằng nhau {a,b}.
Jack Aidley

5
@ jpmc26: Nếu một người ví dụ như sắp xếp danh sách các sự kiện theo thời gian, thì người ta không cần quan tâm đến việc liệu hoạt động sắp xếp có ổn định hay không để quan tâm đến việc mỗi sự kiện xuất hiện chính xác một lần trong đầu vào, tương tự xuất hiện chính xác một lần trong đầu ra. Một số thao tác (như tìm và loại bỏ các sự kiện trùng lặp) có thể yêu cầu sử dụng một thứ tự hoàn chỉnh, nhưng trong nhiều trường hợp khác, có thể chấp nhận liệt kê các sự kiện đồng thời theo thứ tự tùy ý, nhưng không được sao chép hoặc bỏ qua chúng.
supercat

2
@supercat Áp dụng minmaxcho bất cứ điều gì ngoại trừ dấu thời gian (phím sắp xếp) trong kịch bản đó không có ý nghĩa gì. Bản thân các sự kiện (các đối tượng) thậm chí không thể so sánh được nếu sự bình đẳng không bao hàm sự thay thế lẫn nhau. Cách duy nhất {min(a, b), max(a, b)}làm cho bất kỳ ý nghĩa như một cơ chế loại là nếu các đối tượng được hoán đổi.
jpmc26

62

Câu trả lời này giải thích tại sao mã đã cho sai từ quan điểm chuẩn C ++, nhưng nó nằm ngoài ngữ cảnh.

Xem câu trả lời của @ TC để được giải thích theo ngữ cảnh.


Tiêu chuẩn định nghĩa std::max(a, b)như sau [alg.min.max] (nhấn mạnh là của tôi):

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

Yêu cầu : Loại T là LessThanComparable (Bảng 18).

Trả về : Giá trị lớn hơn.

Lưu ý : Trả về đối số đầu tiên khi các đối số tương đương.

Tương đương ở đây có nghĩa !(a < b) && !(b < a)true [alg.sorting # 7] .

Cụ thể, nếu abtương đương, cả hai a < bb < afalse, do đó, giá trị bên phải :sẽ được trả về trong toán tử điều kiện, do đó aphải ở bên phải, vì vậy:

a < b ? b : a

... dường như là câu trả lời đúng. Đây là phiên bản được sử dụng bởi libstdc ++libc ++ .

Vì vậy, thông tin trong trích dẫn của bạn có vẻ sai theo tiêu chuẩn hiện tại, nhưng bối cảnh được xác định có thể khác nhau.


4
Liên kết Godbolt giải thích vấn đề (cảm ơn @songyuanyao cho định nghĩa của X).
Holt

1
@JackAidley Tôi đã chỉnh sửa câu trả lời để xác định rằng lý do nhắm vào tiêu chuẩn hiện tại.
Holt

@codekaizer Tôi thực sự đã đề cập đến "Nếu chúng ta định nghĩa đẳng thức (a, b) là! comp (a, b) &&! comp (b, a)" . Tôi đã thay đổi liên kết thành một trích dẫn tốt hơn (3 dòng dưới đây trong tiêu chuẩn ...).
Holt

1
Ngạc nhiên không ai đã đề cập đến dấu phẩy động, ở đâu a<bb<acả hai đều có thể sai vì chúng không được sắp xếp (một hoặc cả hai NaN, do đó ==cũng sai). Đó có thể được coi là một loại tương đương. liên quan lỏng lẻo: maxsd a, bthực hiện hướng dẫn của x86 a = max(b,a) = b < a ? a : b. ( Hướng dẫn nào cung cấp cho FP không phân nhánh tối đa và tối đa trên x86? ). Lệnh giữ cho toán hạng nguồn (cái thứ 2) không được sắp xếp, do đó, một vòng lặp trên một mảng sẽ cung cấp cho bạn NaN nếu có bất kỳ NaN nào. Nhưng max_seen = max(max_seen, a[i])sẽ bỏ qua NaNs.
Peter Cordes


21

Điểm cần trả về khi chúng tương đương nhau; std::maxphải trả lại a(tức là đối số đầu tiên) cho trường hợp này.

Nếu chúng là tương đương, trả về a.

Vì vậy, a < b ? b : anên được sử dụng; mặt khác, b < a ? a : b;sẽ trả lại bkhông chính xác.

(Như @Holt nói, trích dẫn có vẻ ngược lại.)

"Hai giá trị tương đương nhưng không bằng nhau" có nghĩa là chúng có cùng giá trị khi được so sánh, nhưng chúng di chuyển là các đối tượng khác nhau ở một số khía cạnh khác.

ví dụ

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
Bạn có thể vui lòng giải thích tại sao std::max(a, b)phải quay lại a, nếu abtương đương?
眠 り ネ

4
@ ネ ロ - Đó chỉ là một lựa chọn tùy ý về phần tiêu chuẩn . Mặc dù đó là một chút tranh cãi nếu nó là một trong những tốt.
Người kể chuyện - Unslander Monica

Có phải chỉ có tôi hay điều này mâu thuẫn với câu hỏi? Nếu abtương đương, thì !(a < b) && !(b < a)đúng, vậy a < bb < asai, vậy ...?
Holt

2
@ ネ ロ Tôi cho rằng tiêu chuẩn chỉ muốn làm cho nó xác định; khi chúng tương đương với cái nào sẽ được trả lại.
songyuanyao

1
cảm ơn vì đã làm mới trí nhớ của tôi về lý do tại sao một đối tượng sẽ "tương đương" nhưng không "bằng".
Jeff Walker
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.