template<class T> constexpr T max(T l, T r) {return l < r ? r : l;} template<class T> constexpr T max(T l, T r) {return l < r ? r : l;} T max(T)(T a, T b) { return a < b ? b : a; }
without requiring explicit constexpr annotations and with less noisy template syntax ;).Or what edflsafoiewq said: https://news.ycombinator.com/item?id=16721559
It is however trivial to write a version that works with distinct types, if that were really what you want.
template<class L, class R>
constexpr std::common_type_t<L, R> max(L l, R r) {return l < r ? r : l;}This is a property of c++ implicit constructor rules, it is not unique to this function. In most cases this is something you want to avoid but for integer promotion it can some times be useful.
int* x = malloc(5 * sizeof (int));
because in C++ you cannot implicitly cast a void pointer. max<int>(-1, 2u) // => 2All the crazyness is in order to support both constant expressions (and keep them constant expressions) and non-constant expressions with the same max() macro.
>The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed (provided that appropriate function arguments are given).