Boost C++ Libraries: Ticket #11149: boost::multiprecision compilation fail with std::max https://svn.boost.org/trac10/ticket/11149 <p> pseudo code to reproduce: </p> <p> typedef boost::multiprecision::number&lt;boost::multiprecision::cpp_dec_float&lt;50&gt; &gt; cpp_dec_float_50; using std::max; cpp_dec_float_50 x, y=max(x, 2*x); </p> <p> Fails to compile </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/11149 Trac 1.4.3 John Maddock Sat, 28 Mar 2015 16:32:48 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/11149#comment:1 https://svn.boost.org/trac10/ticket/11149#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">wontfix</span> </li> </ul> <p> This is to be expected, and is a side effect of returning expression templates from arithmetic operators, as mentioned in the introduction (<a href="http://www.boost.org/doc/libs/1_57_0/libs/multiprecision/doc/html/boost_multiprecision/intro.html#boost_multiprecision.intro.expression_templates">http://www.boost.org/doc/libs/1_57_0/libs/multiprecision/doc/html/boost_multiprecision/intro.html#boost_multiprecision.intro.expression_templates</a>) template argument type deduction may fail when passing the result of an expression to a template function. </p> <p> The workarounds are either: </p> <ul><li>Use a type with expression templates turned off - in your case that would be <code>number&lt;cpp_dec_float_50::backend_type, et_off&gt;</code> </li><li>Explicitly specify the template argumnent type for the call - so <code>std::max&lt;cpp_dec_float_50&gt;(x, 2*x)</code>, or: </li><li>Cast expressions prior to the call: <code>std::max(x, static_cast&lt;cpp_dec_float_50&gt;(2*x))</code>. </li></ul><p> I realise that the last 2 may not be possible if you don't control the code where the issue occurs, and that the first may have a performance impact (much lessened in C++11 though with move-semantics), but the only other alternative I can think of is to overload std::max - but that's not permitted by a strict reading of the standard I believe. </p> <p> Closing for now.... if a lot of folks fall into this trap I may reconsider </p> Ticket chtz@… Sun, 29 Mar 2015 20:37:53 GMT <link>https://svn.boost.org/trac10/ticket/11149#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:2</guid> <description> <p> Just some notes: First of all a crossreference to original issue: <a class="ext-link" href="http://eigen.tuxfamily.org/bz/show_bug.cgi?id=982"><span class="icon">​</span>http://eigen.tuxfamily.org/bz/show_bug.cgi?id=982</a> </p> <p> About overloading std::max: That is indeed (at least) bad style, however, you can very well implement a max/min function in your own namespace. Then the following would be possible (due to ADL): </p> <pre class="wiki"> using std::max; cpp_dec_float_50 x, y = max(x, 2*x); </pre><p> Unfortunately, ADL does not work when writing (max) instead of max, which we originally did in Eigen (we replaced this by another mechanism meanwhile). </p> <p> I guess, we'll need to adapt our add &lt;Scalar&gt; arguments to our min/max-calls anyways, if we want to support ET-types. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Mon, 30 Mar 2015 08:50:04 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:3</guid> <description> <p> I'm quite happy to add min/max to boost::multiprecision namespace, I didn't because my gut feeling was that folks wouldn't be relying on ADL to find those (why would they? The std:: ones are perfectly satisfactory). And as you say, for compilers that that define min/max as macros, the needed ()'s break ADL lookup. </p> <p> I'm curious, what's the other mechanism you used in this case? </p> </description> <category>Ticket</category> </item> <item> <author>chtz@…</author> <pubDate>Mon, 30 Mar 2015 14:58:52 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:4</guid> <description> <p> std::max/min are satisfactory, except for the fact that they don't accept ETs. Also, if they happen to be called with matching ETs, you have to evaluate both expressions (which you have to, anyways -- unless you have an extra clever operator&lt; overload), but the result will be evaluated once more. </p> <p> In Eigen we encapsulated max/min to maxi/mini functions in a separate namespace. They are implemented using ADL with an empty macro preventing max()/min() macro expansions. We require ADL, since we support some scalar types which define max and min in their own namespace. </p> <p> I guess, you also define functions such as sqrt in your own namespace, don't you? </p> </description> <category>Ticket</category> </item> <item> <author>chtz@…</author> <pubDate>Mon, 30 Mar 2015 15:00:34 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:4</guid> <description> <p> std::max/min are satisfactory, except for the fact that they don't accept ETs. Also, if they happen to be called with matching ETs, you have to evaluate both expressions (which you have to, anyways -- unless you have an extra clever operator&lt; overload), but the result will be evaluated once more. </p> <p> In Eigen we encapsulated max/min to maxi/mini functions in a separate namespace. They are implemented using ADL with an empty macro preventing max()/min() macro expansions. We require ADL, since we support some scalar types which define max and min in their own namespace. </p> <p> I guess, you also define functions such as sqrt in your own namespace, don't you? </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Tue, 16 Feb 2016 17:56:49 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:5</guid> <description> <p> @johnmaddock, I got bit by this bug, too. was there a resolution? i'd prefer to keep et_on if possible. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Tue, 16 Feb 2016 19:38:13 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:6</guid> <description> <p> If you add the following before including the Eigen headers does it fix things? </p> <pre class="wiki">namespace boost { namespace multiprecision { template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; min(const number&lt;Backend, et_on&gt;&amp; arg, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a) { number&lt;Backend, et_on&gt; t(a); return (std::min)(arg, t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const number&lt;Backend, et_on&gt;&amp; a) { number&lt;Backend, et_on&gt; t(arg); return (std::min)(arg, a); } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { number&lt;Backend, et_on&gt; t1(arg), t2(a); return (std::min)(arg, a); } template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; max(const number&lt;Backend, et_on&gt;&amp; arg, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a) { number&lt;Backend, et_on&gt; t(a); return (std::max)(arg, t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const number&lt;Backend, et_on&gt;&amp; a) { number&lt;Backend, et_on&gt; t(arg); return (std::max)(arg, a); } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { number&lt;Backend, et_on&gt; t1(arg), t2(a); return (std::max)(arg, a); } } } </pre> </description> <category>Ticket</category> </item> <item> <author>chtz@…</author> <pubDate>Tue, 16 Feb 2016 20:01:07 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:7</guid> <description> <p> Just FYI: We worked around the issue in the development branch of Eigen (see discussion of our bug entry). I guess the solution in comment 6 would have worked as well (after changing some of the arguments). You could end up with some unecessary copies however -- though these should usually be optimized away by RVO. </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Tue, 16 Feb 2016 21:09:49 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:8</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:6" title="Comment 6">johnmaddock</a>: thanks for the quick reply, john. i tried the code, and couldn't get off the ground. the two templates of type </p> <p> <code>template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt;</code> </p> <p> and </p> <p> <code>template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt;</code> </p> <p> (third and last) have undefined identifier Backend. </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Tue, 16 Feb 2016 21:14:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:9</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:7" title="Comment 7">chtz@…</a>: </p> <blockquote class="citation"> <p> Just FYI: We worked around the issue in the development branch of Eigen (see discussion of our bug entry). I guess the solution in comment 6 would have worked as well (after changing some of the arguments). You could end up with some unecessary copies however -- though these should usually be optimized away by RVO. </p> </blockquote> <p> Thanks for the quick reply, chtz. I get to support older versions of Eigen with <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:6" title="Comment 6">6</a> (John's solution), but just have to wait for Eigen develop to become release to get the official solution. Which do you recommend as a solution? I think I prefer <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:6" title="Comment 6">6</a> for immediate satisfaction, but would love an opinion. </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Tue, 16 Feb 2016 22:53:32 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:10</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:6" title="Comment 6">johnmaddock</a>: </p> <p> hi john, i replaced the number&lt;Backend, et_on&gt; with the deduced type similar to the return type from those two templates: </p> <pre class="wiki">namespace boost { namespace multiprecision { template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; min(const number&lt;Backend, et_on&gt;&amp; arg, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a) { number&lt;Backend, et_on&gt; t(a); return (std::min)(arg, t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const number&lt;Backend, et_on&gt;&amp; a) { number&lt;Backend, et_on&gt; t(arg); return (std::min)(arg, a); } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { using N = typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type; N t1(arg), t2(a); return (std::min)(arg, a); } template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; max(const number&lt;Backend, et_on&gt;&amp; arg, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a) { number&lt;Backend, et_on&gt; t(a); return (std::max)(arg, t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const number&lt;Backend, et_on&gt;&amp; a) { number&lt;Backend, et_on&gt; t(arg); return (std::max)(arg, a); } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { using N = typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type; N t1(arg), t2(a); return (std::max)(arg, a); } } } </pre><p> These type replacements for these two templates appear ok. </p> <p> My use of Eigen for JacobiSVD still fails, due to missing max. I am including the file with the above code before <code>#include &lt;Eigen/Core&gt;</code> or any other Eigen files, so I am still puzzled. I will get a minimal working example together to ensure that the rest of my project is not interfering with this solution. Thanks again for the help. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Wed, 17 Feb 2016 12:58:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:11</guid> <description> <p> Note that this issue can occur with built-in types too: </p> <pre class="wiki"> short sa(1), sb(2), sc(3); short sd = (std::min)(sa, sb + sc); // ambiguous </pre><p> So IMO it is correct to fix this with a typecast at the call site of std::min/max. </p> <p> Which is not to say I won't add the overloads to namespace boost::multiprecision as well... once I have them correct and move enabled etc... </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Wed, 17 Feb 2016 14:13:29 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:12</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:11" title="Comment 11">johnmaddock</a>: </p> <p> it sounds like my best bet then is to use the develop branch of Eigen, or to turn off expression templates until the fix becomes release code? </p> <p> note that the code you posted did indeed allow me to compute max() in my code, but still not in the context of eigen's svd. </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Wed, 17 Feb 2016 16:41:17 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:13</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:11" title="Comment 11">johnmaddock</a>: </p> <p> I have prepared a minimal working example, demonstrating your comment 11, as well as the ongoing problem with Eigen. </p> <pre class="wiki">// 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@nd.edu // Feb 2016 #include &lt;algorithm&gt; #include &lt;cmath&gt; #include &lt;boost/multiprecision/mpfr.hpp&gt; using mpfr_float = boost::multiprecision::number&lt;boost::multiprecision::mpfr_float_backend&lt;0&gt;, boost::multiprecision::et_on&gt;; // 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 &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; min(const number&lt;Backend, et_on&gt;&amp; arg, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a) { number&lt;Backend, et_on&gt; t(a); return (std::min)(arg, t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const number&lt;Backend, et_on&gt;&amp; a) { number&lt;Backend, et_on&gt; t(arg); return (std::min)(arg, a); } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { using N = typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type; N t1(arg), t2(a); return (std::min)(arg, a); } template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; max(const number&lt;Backend, et_on&gt;&amp; arg, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a) { number&lt;Backend, et_on&gt; t(a); return (std::max)(arg, t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const number&lt;Backend, et_on&gt;&amp; a) { number&lt;Backend, et_on&gt; t(arg); return (std::max)(arg, a); } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { using N = typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type; N t1(arg), t2(a); return (std::max)(arg, a); } } } // include AFTER the above templates #include &lt;Eigen/Dense&gt; // 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&lt;&gt; struct NumTraits&lt;mpfr_float&gt; : GenericNumTraits&lt;mpfr_float&gt; { 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&lt;mpfr_float, Eigen::Dynamic, Eigen::Dynamic&gt; A(2,2); A &lt;&lt; 2, 1, 1, 2; // populate it // this is the offending line. Eigen attempts to call max, but cannot see the above templates. Eigen::JacobiSVD&lt;Eigen::Matrix&lt;mpfr_float, Eigen::Dynamic, Eigen::Dynamic&gt;&gt; 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; } </pre> </description> <category>Ticket</category> </item> <item> <author>chtz@…</author> <pubDate>Wed, 17 Feb 2016 17:02:47 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:14</guid> <description> <p> First of all, in all patches/examples you wrote above, you need to replace the arguments to <code>(std::min)(arg, a);</code> by the appropriate <code>t,t1,t2</code>. For a clean solution you should actually implement <code>min,max</code> similar to the way you implement <code>atan2</code>. </p> <p> However, that will indeed still not work with Eigen3.2, since (as you noted) we use something like <code>(max)(a,b)</code> which prevents ADL (for whatever reason ...) I don't really like having to fix this in Eigen3.2, but actually the <code>using std::max; ... (max)(A,B)</code> we are currently doing is more or less pointless, here. </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Wed, 17 Feb 2016 19:47:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:15</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:14" title="Comment 14">chtz@…</a>: </p> <p> i checked out the eigen develop 3.3-beta1 code, and confirm that this issue is fixed, with no need for the min/max that John Maddock provided in comment 6. comment 6 does still resolve the problem for min/max'ing with et_on not in the context of eigen. </p> <p> a workaround for me might consist of providing a compile-time configure option for my library for turning off the expression templates for Boost.Multiprecision. if they are on, require a minimum version of eigen. otherwise, let it ride with any version 3.2 or later. i have an m4 macro for autoconf which finds eigen (does eigen provide such a macro? i didn't find one), and the et_on/off requirement could be written into the call. </p> <p> any thoughts? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Wed, 17 Feb 2016 20:03:21 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:16 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:16</guid> <description> <p> As noted above, the overloads I gave before are buggy... which is what happens when you try to just type in a quick fix :( </p> <p> This is what I plan to test: </p> <pre class="wiki">template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; min(const number&lt;Backend, et_on&gt;&amp; a, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; b) { number&lt;Backend, et_on&gt; t(b); if(a &lt; t) return a; return BOOST_MP_MOVE(t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a, const number&lt;Backend, et_on&gt;&amp; b) { number&lt;Backend, et_on&gt; t(a); if(t &lt; b) return BOOST_MP_MOVE(t); return b; } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { number&lt;Backend, et_on&gt; t1(a), t2(b); if(t1 &lt; t2) return BOOST_MP_MOVE(t1); return BOOST_MP_MOVE(t2); } template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; max(const number&lt;Backend, et_on&gt;&amp; a, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; b) { number&lt;Backend, et_on&gt; t(b); if(a &gt; t) return a; return BOOST_MP_MOVE(t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a, const number&lt;Backend, et_on&gt;&amp; b) { number&lt;Backend, et_on&gt; t(a); if(t &gt; b) return BOOST_MP_MOVE(t); return b; } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { number&lt;Backend, et_on&gt; t1(a), t2(b); if(t1 &gt; t2) return BOOST_MP_MOVE(t1); return BOOST_MP_MOVE(t2); } </pre><p> In addition you will need: </p> <pre class="wiki">namespace std{ using boost::multiprecision::min; using boost::multiprecision::max; </pre><p> Which is not valid C++ strictly speaking, but should get current/older eigen releases working... again untested... I will get to that sometime, but you may be quicker than me ;) </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Wed, 17 Feb 2016 20:29:07 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:17 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:17</guid> <description> <p> thanks very much for continuing to troubleshoot this with me! </p> <p> i had to change the third and sixth templates, replacing <code>number&lt;Backend, et_on&gt;</code> with <code>typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type</code>. </p> <p> without the </p> <pre class="wiki">namespace std{ using boost::multiprecision::min; using boost::multiprecision::max; </pre><p> i still get <code>error: no matching function for call to 'max'</code>. </p> <p> with it, <code>error: call to 'max' is ambiguous</code>. </p> <pre class="wiki">/usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/src/SVD/JacobiSVD.h:876:66: error: call to 'max' is ambiguous RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), ^~~~~ /usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/src/SVD/JacobiSVD.h:578:7: note: in instantiation of member function 'Eigen::JacobiSVD&lt;Eigen::Matrix&lt;boost::multiprecision::number&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt;, boost::multiprecision::expression_template_option::et_on&gt;, -1, -1, 0, -1, -1&gt;, 2&gt;::compute' requested here compute(matrix, computationOptions); ^ mwe_eigen_mpfr_max.cpp:161:78: note: in instantiation of member function 'Eigen::JacobiSVD&lt;Eigen::Matrix&lt;boost::multiprecision::number&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt;, boost::multiprecision::expression_template_option::et_on&gt;, -1, -1, 0, -1, -1&gt;, 2&gt;::JacobiSVD' requested here Eigen::JacobiSVD&lt;Eigen::Matrix&lt;mpfr_float, Eigen::Dynamic, Eigen::Dynamic&gt;&gt; svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:2662:1: note: candidate function [with _Tp = boost::multiprecision::detail::expression&lt;boost::multiprecision::detail::function, boost::multiprecision::detail::abs_funct&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt; &gt;, boost::multiprecision::number&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt;, boost::multiprecision::expression_template_option::et_on&gt;, void, void&gt;] max(const _Tp&amp; __a, const _Tp&amp; __b) ^ mwe_eigen_mpfr_max.cpp:89:2: note: candidate function [with tag = boost::multiprecision::detail::function, A1 = boost::multiprecision::detail::abs_funct&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt; &gt;, A2 = boost::multiprecision::number&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt;, boost::multiprecision::expression_template_option::et_on&gt;, A3 = void, A4 = void, tagb = boost::multiprecision::detail::function, A1b = boost::multiprecision::detail::abs_funct&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt; &gt;, A2b = boost::multiprecision::number&lt;boost::multiprecision::backends::mpfr_float_backend&lt;0, allocate_dynamic&gt;, boost::multiprecision::expression_template_option::et_on&gt;, A3b = void, A4b = void] max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const ^ </pre><p> the code i tested is below for reference. </p> <pre class="wiki">#include &lt;algorithm&gt; #include &lt;cmath&gt; #include &lt;boost/multiprecision/mpfr.hpp&gt; using mpfr_float = boost::multiprecision::number&lt;boost::multiprecision::mpfr_float_backend&lt;0&gt;, boost::multiprecision::et_on&gt;; // changing et_on to et_off allows this code to compile. // the problem with min/max is with expression templates. namespace boost { namespace multiprecision { template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; min(const number&lt;Backend, et_on&gt;&amp; a, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; b) { number&lt;Backend, et_on&gt; t(b); if(a &lt; t) return a; return BOOST_MP_MOVE(t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a, const number&lt;Backend, et_on&gt;&amp; b) { number&lt;Backend, et_on&gt; t(a); if(t &lt; b) return BOOST_MP_MOVE(t); return b; } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type min(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { // number&lt;Backend, et_on&gt; t1(a), t2(b); typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type t1(arg), t2(a); if(t1 &lt; t2) return BOOST_MP_MOVE(t1); return BOOST_MP_MOVE(t2); } template &lt;class Backend, class tag, class A1, class A2, class A3, class A4&gt; inline number&lt;Backend, et_on&gt; max(const number&lt;Backend, et_on&gt;&amp; a, const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; b) { number&lt;Backend, et_on&gt; t(b); if(a &gt; t) return a; return BOOST_MP_MOVE(t); } template &lt;class tag, class A1, class A2, class A3, class A4, class Backend&gt; inline number&lt;Backend, et_on&gt; max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; a, const number&lt;Backend, et_on&gt;&amp; b) { number&lt;Backend, et_on&gt; t(a); if(t &gt; b) return BOOST_MP_MOVE(t); return b; } template &lt;class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b&gt; inline typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type max(const detail::expression&lt;tag, A1, A2, A3, A4&gt;&amp; arg, const detail::expression&lt;tagb, A1b, A2b, A3b, A4b&gt;&amp; a) { // number&lt;Backend, et_on&gt; t1(a), t2(b); typename detail::expression&lt;tag, A1, A2, A3, A4&gt;::result_type t1(arg), t2(a); if(t1 &gt; t2) return BOOST_MP_MOVE(t1); return BOOST_MP_MOVE(t2); } }} namespace std{ using boost::multiprecision::min; using boost::multiprecision::max; } // include AFTER the above templates #include &lt;Eigen/Dense&gt; // 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&lt;&gt; struct NumTraits&lt;mpfr_float&gt; : GenericNumTraits&lt;mpfr_float&gt; { 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())); } }; } #include &lt;iostream&gt; // so i can print the V result of the SVD. not strictly necessary for this MWE int main() { // make a 2x2 dynamic matrix Eigen::Matrix&lt;mpfr_float, Eigen::Dynamic, Eigen::Dynamic&gt; A(2,2); A &lt;&lt; 2, 1, 1, 2; // populate it // this is the offending line. Eigen attempts to call max, but cannot see the above templates, or has ambiguous call to max, depending on the presence of the using directives in namespace std. Eigen::JacobiSVD&lt;Eigen::Matrix&lt;mpfr_float, Eigen::Dynamic, Eigen::Dynamic&gt;&gt; svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); std::cout &lt;&lt; svd.matrixV(); return 0; } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Thu, 18 Feb 2016 18:41:57 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:18 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:18</guid> <description> <p> OK, I finally got around to doing some actual testing ;) It turns out it's really easy to break std::min/max if these overloads are also present. However, the patch here: <a class="ext-link" href="https://github.com/boostorg/multiprecision/commit/f57bd6b31a64787425ec891bd2ceb536c9036f72"><span class="icon">​</span>https://github.com/boostorg/multiprecision/commit/f57bd6b31a64787425ec891bd2ceb536c9036f72</a> gets your test case compiling OK as long as the </p> <pre class="wiki">namespace std{ using boost::multiprecision::min; using boost::multiprecision::max; } </pre><p> Is also present prior to including Eigen. </p> </description> <category>Ticket</category> </item> <item> <author>chtz@…</author> <pubDate>Thu, 18 Feb 2016 22:00:02 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:19 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:19</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:15" title="Comment 15">dbrake@…</a>: </p> <blockquote class="citation"> <p> a workaround for me might consist of providing a compile-time configure option for my library for turning off the expression templates for Boost.Multiprecision. if they are on, require a minimum version of eigen. otherwise, let it ride with any version 3.2 or later. i have an m4 macro for autoconf which finds eigen (does eigen provide such a macro? i didn't find one), and the et_on/off requirement could be written into the call. </p> </blockquote> <p> Eigen does not provide m4 macros. There is a preprocessor macro <code>EIGEN_VERSION_AT_LEAST(x,y,z)</code> and we provide a cmake module FindEigen3.cmake which also checks for the version number. The latter should be relativly easy to adapt to any language with basic regex support. </p> </description> <category>Ticket</category> </item> <item> <author>dbrake@…</author> <pubDate>Thu, 18 Feb 2016 22:27:22 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11149#comment:20 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11149#comment:20</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:18" title="Comment 18">johnmaddock</a>: </p> <p> I tested your patch with Boost version 1.58 and 1.59, against Eigen 3.2.7 and 3.3-beta1, and it totally fixes the problem, both for the small example above, and for my project at large. I'm calling this problem solved. Thanks John! </p> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11149#comment:19" title="Comment 19">chtz</a>: </p> <p> Very good, thanks for pointing this macro out to me chtz! </p> <p> And thanks to all the generous developers who make free software possible. </p> <hr /> <p> My conclusion: this bug is fixed, by any one of: </p> <ul><li>using 3.3-beta1 (or equivalent release) of Eigen, </li><li>patching Boost.Multiprecision with <a class="ext-link" href="https://github.com/boostorg/multiprecision/commit/f57bd6b31a64787425ec891bd2ceb536c9036f72"><span class="icon">​</span>https://github.com/boostorg/multiprecision/commit/f57bd6b31a64787425ec891bd2ceb536c9036f72</a> combined with the non-conforming using statements above, or </li><li>turning off expression templates. </li></ul> </description> <category>Ticket</category> </item> </channel> </rss>