[ACCEPTED]-std::max() and std::min() not constexpr-constexpr

Accepted answer
Score: 21

std::min and std::max are constexpr in C++14, which obviously 2 means there isn't a good reason (these days) not 1 to have them constexpr. Problem solved :-)

Score: 13

Critical Update

The below analysis is wrong, because it confuses one important thing. The following statement I did missed one 59 important detail, which requires an entirely 58 different answer.

The unnamed reference max returns 57 will refer to that operand.

The problem here 56 is that function invocation substitution is done at that point. If the invocation 55 susbstitution would include the lvalue to 54 rvalue conversion on that glvalue that max yields, everything 53 would be fine, because reading from a glvalue 52 that refers to a temporary not of static 51 storage duration is fine during computation of the constant expression. But since the 50 read happens outside of function invocation 49 substitution, the result of function invocation 48 substitution is an lvalue. The respective text 47 of the spec says

A reference constant expression 46 is an lvalue core constant expression that 45 designates an object with static storage 44 duration or a function.

But the reference 43 that max returns yields an lvalue that designates 42 an object of unspecified storage duration. Function 41 invocation substitution is required to yield 40 a constant expression, not merely a core constant expression. So 39 max(sizeof(A), sizeof(B)) is not guaranteed to work.

The following (older) text needs to be read taking the above into account.


I can't see 38 any reason at the moment why you wouldn't 37 want to stick a constexpr there. Anyway, the following 36 code definitely is useful

template<typename T> constexpr
T const& max(T const& a, T const& b) {
  return a > b ? a : b;
}

Contrary to what 35 other answers write, I think this is legal. Not 34 all instantiations of max are required to be 33 constexpr functions. The current n3242 says

If 32 the instantiated template specialization 31 of a constexpr function template or member 30 function of a class template would fail 29 to satisfy the requirements for a constexpr 28 function or constexpr constructor, that 27 specialization is not a constexpr function 26 or constexpr constructor.

If you call the 25 template, argument deduction will yield 24 a function template specialization. Calling 23 it will trigger function invocation substitution. Consider the following 22 call

int a[max(sizeof(A), sizeof(B))];

It will first do an implicit conversion 21 of the two size_t prvalues to the two reference 20 parameters, binding both references to temporary 19 objects storing their value. The result 18 of this conversion is a glvalue for each case that 17 refers to a temporary object (see 4p3). Now 16 function invocation substitution takes those 15 two glvalues and substitutes all occurences 14 of a and b in the function body by those glvalues

return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);

The 13 condition will require lvalue to rvalue 12 conversions on these glvalues, which are 11 allowed by 5.19p2

  • a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression

The conditional expression 10 will yield a glvalue to either the first 9 or second operand. The unnamed reference 8 max returns will refer to that operand. And 7 the final lvalue to rvalue conversion happening 6 in the array dimension size specification 5 will be valid by the same rule quoted above.


Note 4 that initializer_list currently doesn't have constexpr member functions. This 3 is a known limitation and will be handled 2 post-C++0x, most likely making those members 1 constexpr.

Score: 1

The inclusion of constexpr versions of std::min() and std::max() in C++14 7 demonstrates that there's no fundamental 6 obstacle to making (versions of) these functions 5 constexpr. It seems that this wasn't considered 4 early enough when constexpr was added to C++11.

Obviously, for 3 the versions where a comparison function 2 is provided, that function must itself be 1 constexpr for the template expansion to succeed.

More Related questions