
<< Background ... >> Way back in 1995, Scott Meyers issued a challenge to the C++ community to build a better min/max utility [1]. In 2003, Andrei took up the challenge [2], but his results were unsatisfactory for reasons both technical and aesthetic [3]. In 2005, I wrote about some tricks you can do with the conditional operator [4]. Andrei suggested a way the tricks could be used to finally resolve Scott's min/max challenge. Still, the nagging lvalue/rvalue problems remained. (Consider that for some user-defined type A, this: "A const &a = std::min(A(1),A(2));" causes the reference to "a" to dangle.) << The Present ... >> Last week, at Scott's prodding, I took the issue up again and finally resolved the lvalue/rvalue problem. The result is a macro MAX(a,b) that behaves *exactly* like ((a)<(b)?(b):(a)), except that it does not reevaluate its arguments. It has the following advantages over std::max: 1) It supports both const and non-const arguments (including mixing the two in a single call). 2) It supports arguments of different types. 3) The expression type of MAX(a,b) is naturally identical to "((a)<(b)?(b):(a))", relying on the compiler's type promotion rules. 4) The rvalue/lvalue-ness of MAX(a,b) is identical to "((a)<(b)?(b):(a))", making it possible to use it on the left side of an assignment, for instance: "MAX(a,b) = 1". This also means that dangling references are impossible. The code is 100% C++98 compliant, and should work on gcc and comeau. (msvc will need some work-arounds.) The code is below. << The Future ... >> Is there interest in turning this into a BOOST_MIN/BOOST_MAX library? << The Code >> #include <boost/type.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/or.hpp> #include <boost/type_traits/is_array.hpp> #include <boost/type_traits/is_abstract.hpp> template<typename Type> boost::type<Type>* encode_type(Type &) { return 0; } template<typename Type> boost::type<Type const>* encode_type(Type const &) { return 0; } /////////////////////////////////////////////////////////////////////////////// // max_impl template<typename Ret, typename Left, typename Right> struct max_impl { max_impl(Left &left, Right &right) : left_(left) , right_(right) {} struct private_type_ {}; // can't ever return an array or an abstract type by value typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::mpl::or_<boost::is_abstract<Ret>, boost::is_array<Ret> > , private_type_ , Ret >::type value_type; operator value_type() { return this->left_ < this->right_ ? this->right_ : this->left_; } operator Ret &() const { return this->left_ < this->right_ ? this->right_ : this->left_; } private: Left &left_; Right &right_; }; /////////////////////////////////////////////////////////////////////////////// // max_fun template<typename Ret, typename Left, typename Right> max_impl<Ret, Left, Right> max_fun(Left &left, Right &right, boost::type<Ret> *) { return max_impl<Ret, Left, Right>(left, right); } template<typename Ret, typename Left, typename Right> max_impl<Ret, Left const, Right> max_fun(Left const &left, Right &right, boost::type<Ret> *) { return max_impl<Ret, Left const, Right>(left, right); } template<typename Ret, typename Left, typename Right> max_impl<Ret, Left, Right const> max_fun(Left &left, Right const &right, boost::type<Ret> *) { return max_impl<Ret, Left, Right const>(left, right); } template<typename Ret, typename Left, typename Right> max_impl<Ret, Left const, Right const> max_fun(Left const &left, Right const &right, boost::type<Ret> *) { return max_impl<Ret, Left const, Right const>(left, right); } #define MAX(a,b)\ (true\ ? max_fun((a), (b), \ (true? 0 : encode_type(true? (a) : (b))))\ : (true? (a) : (b))) [1] http://www.aristeia.com/Papers/C++ReportColumns/jan95.pdf [2] http://www.ddj.com/dept/cpp/184403774 [3] Andrei's solution ignores lvalue/rvalue issues as raised in Francis Glassborow's c++std-lib-15426, and it depends on Loki, requiring a large amount of template code that largely duplicates the type promotion logic already present in the compiler. [4] http://www.artima.com/cppsource/foreach.html -- Eric Niebler Boost Consulting www.boost-consulting.com