Re: [Boost-bugs] [Boost C++ Libraries] #11149: boost::multiprecision compilation fail with std::max

Subject: Re: [Boost-bugs] [Boost C++ Libraries] #11149: boost::multiprecision compilation fail with std::max
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2016-02-17 16:41:17


#11149: boost::multiprecision compilation fail with std::max
-------------------------------+----------------------------
  Reporter: minorlogic@… | Owner: johnmaddock
      Type: Bugs | Status: closed
 Milestone: To Be Determined | Component: multiprecision
   Version: Boost 1.57.0 | Severity: Showstopper
Resolution: wontfix | Keywords:
-------------------------------+----------------------------

Comment (by dbrake@…):

 Replying to [comment:11 johnmaddock]:


 I have prepared a minimal working example, demonstrating your comment 11,
 as well as the ongoing problem with Eigen.


 {{{
 // this file is intended to be compiled against boost multiprecision and
 eigen.
 // it demonstrates how eigen fails to find the correct overload of
 min/max.

 // example compile command
 // g++ -std=c++11 -I/usr/local/Cellar/eigen/3.2.7/include/eigen3/
 -I/usr/local/Cellar/boost/1.58.0/include/ mwe_eigen_mpfr_max.cpp -lmpfr

 // this example fails to compile under clang on osx 10.11
 // Configured with:
 --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-
 include-dir=/usr/include/c++/4.2.1
 // Apple LLVM version 7.0.2 (clang-700.1.81)
 // Target: x86_64-apple-darwin15.3.0
 // Thread model: posix

 // prepared by Daniel Brake
 // University of Notre Dame
 // dbrake_at_[hidden]
 // Feb 2016

 #include <algorithm>
 #include <cmath>
 #include <boost/multiprecision/mpfr.hpp>

 using mpfr_float =
 boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0>,
 boost::multiprecision::et_on>;
 // changing et_on to et_off allows this code to compile.
 // the problem with min/max is with expression templates.


 // from John Maddock, a boost multiprecision author, via email 2016.02.16
 and
 // https://svn.boost.org/trac/boost/ticket/11149
 namespace boost { namespace multiprecision {

 template <class Backend, class tag, class A1, class A2, class A3, class
 A4>
         inline number<Backend, et_on> min(const number<Backend, et_on>&
 arg, const detail::expression<tag, A1, A2, A3, A4>& a)
         {
                 number<Backend, et_on> t(a);
                 return (std::min)(arg, t);
         }
 template <class tag, class A1, class A2, class A3, class A4, class
 Backend>
         inline number<Backend, et_on> min(const detail::expression<tag,
 A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)
         {
                 number<Backend, et_on> t(arg);
                 return (std::min)(arg, a);
         }
 template <class tag, class A1, class A2, class A3, class A4, class tagb,
 class A1b, class A2b, class A3b, class A4b>
         inline typename detail::expression<tag, A1, A2, A3,
 A4>::result_type min(const detail::expression<tag, A1, A2, A3, A4>& arg,
 const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)
         {
                 using N = typename detail::expression<tag, A1, A2, A3,
 A4>::result_type;
                 N t1(arg), t2(a);
                 return (std::min)(arg, a);
         }

 template <class Backend, class tag, class A1, class A2, class A3, class
 A4>
         inline number<Backend, et_on> max(const number<Backend, et_on>&
 arg, const detail::expression<tag, A1, A2, A3, A4>& a)
         {
                 number<Backend, et_on> t(a);
                 return (std::max)(arg, t);
         }
 template <class tag, class A1, class A2, class A3, class A4, class
 Backend>
         inline number<Backend, et_on> max(const detail::expression<tag,
 A1, A2, A3, A4>& arg, const number<Backend, et_on>& a)
         {
                 number<Backend, et_on> t(arg);
                 return (std::max)(arg, a);
         }
 template <class tag, class A1, class A2, class A3, class A4, class tagb,
 class A1b, class A2b, class A3b, class A4b>
         inline typename detail::expression<tag, A1, A2, A3,
 A4>::result_type max(const detail::expression<tag, A1, A2, A3, A4>& arg,
 const detail::expression<tagb, A1b, A2b, A3b, A4b>& a)
         {
                 using N = typename detail::expression<tag, A1, A2, A3,
 A4>::result_type;
                 N t1(arg), t2(a);
                 return (std::max)(arg, a);
         }

 } }


 // include AFTER the above templates
 #include <Eigen/Dense>

 // reopen the Eigen namespace to provide NumTraits for mpfr_float.
 namespace Eigen {
         // describe mpfr_float to Eigen
         // permits to get the epsilon, dummy_precision, lowest, highest
 functions
         template<> struct NumTraits<mpfr_float> :
 GenericNumTraits<mpfr_float>
         {

                 typedef mpfr_float Real;
                 typedef mpfr_float NonInteger;
                 typedef mpfr_float Nested;
                 enum {
                         IsComplex = 0,
                         IsInteger = 0,
                         IsSigned = 1,
                         RequireInitialization = 1, // yes, require
 initialization, otherwise get crashes
                         ReadCost = 20,
                         AddCost = 30,
                         MulCost = 40
                 };


                 inline static Real highest() {

                         return (mpfr_float(1) - epsilon()) *
 pow(mpfr_float(2),mpfr_get_emax()-1);
                 }

                 inline static Real lowest() {
                         return -highest();
                 }

                 inline static Real dummy_precision()
                 {
                         return pow(
 mpfr_float(10),-int(mpfr_float::default_precision()-3));
                 }

                 inline static Real epsilon()
                 {
                         return
 pow(mpfr_float(10),-int(mpfr_float::default_precision()));
                 }
                 //http://www.manpagez.com/info/mpfr/mpfr-2.3.2/mpfr_31.php
         };

 }


 int main()
 {
         mpfr_float a(1), b(2), c(3);
         using std::max;
          // this line works because of the 6 above templates providing
 min/max.
         auto r = max(a,b*b+c);

         // this line will fail, not finding the call to max. this is
 syntactically similar to the failing eigen call from version 3.2.7.

         auto s = (max)(a,b*b+c);

         // make a 2x2 dynamic matrix
         Eigen::Matrix<mpfr_float, Eigen::Dynamic, Eigen::Dynamic> A(2,2);
         A << 2, 1, 1, 2; // populate it


         // this is the offending line. Eigen attempts to call max, but
 cannot see the above templates.
         Eigen::JacobiSVD<Eigen::Matrix<mpfr_float, Eigen::Dynamic,
 Eigen::Dynamic>> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
         // In file included from mwe_eigen_mpfr_max.cpp:68:
         // In file included from
 /usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/Dense:5:
         // In file included from
 /usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/SVD:24:
         //
 /usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/src/SVD/JacobiSVD.h:876:32:
 error: no matching function for call to 'max'
         return 0;

 }

 }}}

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/11149#comment:13>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:19 UTC