Why use “b < a ? a : b” instead of “a < b ? b : a” to implement max template?

C++Templates

C++ Problem Overview


C++ Templates - The Complete Guide, 2nd Edition introduces the max template:

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

And it explains using “b < a ? a : b” instead of “a < b ? b : a”:

> Note that the max() template according to [StepanovNotes] > intentionally returns “b < a ? a : b” instead of “a < b ? b : a” to > ensure that the function behaves correctly even if the two values are > equivalent but not equal.

How to understand "even if the two values are equivalent but not equal."? “a < b ? b : a” seems have the same result for me.

C++ Solutions


Solution 1 - C++

std::max(a, b) is indeed specified to return a when the two are equivalent.

That's considered a mistake by Stepanov and others because it breaks the useful property that given a and b, you can always sort them with {min(a, b), max(a, b)}; for that, you'd want max(a, b) to return b when the arguments are equivalent.

Solution 2 - C++

This answer explains why the given code is wrong from a C++ standard point-of-view, but it is out of context.

See @T.C.'s answer for a contextual explanation.


The standard defines std::max(a, b) as follows [alg.min.max] (emphasis is mine):

> template constexpr const T& max(const T& a, const T& b); > > Requires: Type T is LessThanComparable (Table 18). > > Returns: The larger value. > > Remarks: Returns the first argument when the arguments are equivalent.

Equivalent here means that !(a < b) && !(b < a) is true [alg.sorting#7].

In particular, if a and b are equivalent, both a < b and b < a are false, so the value on the right of : will be returned in the conditional operator, so a has to be on the right, so:

a < b ? b : a

...seems to be the correct answer. This is the version used by libstdc++ and libc++.

So the information in your quote seems wrong according to the current standard, but the context in which it is defined might be different.

Solution 3 - C++

The point is which one should be returned when they are equivalent; std::max has to return a (i.e. the first argument) for this case.

> If they are equivalent, returns a.

So a < b ? b : a should be used; on the other hand, b < a ? a : b; will return b incorrectly.

(As @Holt said, the quote seems opposite.)

"the two values are equivalent but not equal" means they have the same value when being compared, but they migth be different objects at some other aspects.

e.g.

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNan XiaoView Question on Stackoverflow
Solution 1 - C++T.C.View Answer on Stackoverflow
Solution 2 - C++HoltView Answer on Stackoverflow
Solution 3 - C++songyuanyaoView Answer on Stackoverflow