Nan Xiao
Nan Xiao

Reputation: 17477

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

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.

Upvotes: 163

Views: 14309

Answers (3)

Holt
Holt

Reputation: 37616

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<class T> 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.

Upvotes: 62

T.C.
T.C.

Reputation: 137315

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.

Upvotes: 155

songyuanyao
songyuanyao

Reputation: 172934

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

Upvotes: 22

Related Questions