Boost C++ Libraries: Ticket #10853: problem with detection of const_cast_from https://svn.boost.org/trac10/ticket/10853 <p> According to the documentation for the <code>boost::intrusive::pointer_traits</code> non-standard extensions, <code>pointer_traits&lt;Ptr&gt;::const_cast_from(const UPtr&amp;)</code> should try to call <code>Ptr::const_cast_from(const UPtr&amp;)</code> if it exists, or else use a default. It seems to me that this process fails with compilation error (not only misdetection) when <code>const_cast_from()</code> is a plain static function inside <code>Ptr</code>, as opposed to a function template. To trigger this process and the compilation error, use e.g. <code>front()</code> on an intrusive list. </p> <p> For an example demonstrating this, look at <code>test/bounded_pointer.hpp</code> in the boost intrusive git repo. There, <code>const_cast_from</code> is a template: </p> <pre class="wiki">template&lt;class U&gt; static bounded_pointer const_cast_from(const bounded_pointer&lt;U&gt; &amp;) </pre><p> For me (<code>gcc-4.9.2</code>, <code>clang-3.4</code>), the compilation fails if the signature is changed to: </p> <pre class="wiki">static bounded_pointer const_cast_from(const bounded_pointer&lt;const_val_t&gt; &amp;) </pre><p> For a real program showing this, use the non-dummy version of <code>test/test_list.cpp</code>. (I don't understand why it was commented out.) To clarify, the problem has nothing to do with <code>bounded_pointer</code>, that's just an existing file demonstrating it. </p> <p> Digging a bit into this issue, it appears that the problem is with the mechanism used to detect the presence <code>const_cast_from()</code> inside <code>Ptr</code>. That mechanism is in <code>boost/intrusive/detail/has_member_function_callable_with.hpp</code>. In my case, the error comes from line 200 of that file, saying that the call to <code>const_cast_from</code> is ambiguous: one candidate is the real function, the other candidate is the dummy declared on line 191. I believe the whole point is for overload resolution to prefer the real function to the dummy, which doesn't happen in this case. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10853 Trac 1.4.3 Matei David <matei@…> Fri, 05 Dec 2014 20:44:18 GMT attachment set https://svn.boost.org/trac10/ticket/10853 https://svn.boost.org/trac10/ticket/10853 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">const-cast-from-failure.cpp</span> </li> </ul> Ticket Matei David <matei@…> Fri, 05 Dec 2014 21:16:03 GMT <link>https://svn.boost.org/trac10/ticket/10853#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10853#comment:1</guid> <description> <p> I've isolated the heart of the problem. The attached file demonstrates how overload resolution fails with 2 non-template candidate functions, when both involve non-trivial constructor calls, even though one of them involves ellipses. I imagine the original detection code in <code>boost/intrusive/detail/has_member_function_callable_with.hpp</code> assumed the compiler would prefer the non-ellipses constructor. </p> <p> The bug is triggered in the boost intrusive library as follows: </p> <ol><li>In the docs, the signature for <code>list_node_traits::get_next()</code> is: <pre class="wiki">static node_ptr get_next(const_node_ptr) </pre></li><li>In <code>list::front() const</code>, the following code appears: <pre class="wiki">detail::uncast(node_traits::get_next(this-&gt;get_root_node())) </pre></li><li>As a result, <code>detail::uncast()</code> is called with an argument of type <code>node_ptr</code> (not <code>const_node_ptr</code>!). </li><li>In turn, this triggers the mechanism looking for: <pre class="wiki">node_ptr::const_cast_from(const node_ptr&amp;) </pre></li><li>The documentation doesn't specify such a method should exist. One would assume it is ok to only have a similar function where the argument is <code>const_node_ptr</code> (not <code>node_ptr</code>!): <pre class="wiki">node_ptr::const_cast_from(const const_node_ptr&amp;) </pre></li><li>The existing code tries to detect <code>const_cast_from</code> by passing it an argument of type <code>declval&lt;node_ptr&gt;()</code>. </li><li>Naturally, a constructor exists with the signature: <pre class="wiki">const_node_ptr(const node_ptr&amp;) </pre></li><li>However, the overload resolution code now has to choose between calling the constructor above, or the ellipses constructor from <code>has_member_function_callable_with.hpp:191</code>. </li><li>As the small example demonstrates, the resolution fails with a compile-time error. </li></ol><p> Possible fixes: </p> <ul><li>Update the docs to make it clear <code>node_ptr::const_cast_from(const node_ptr&amp;)</code> should exist. It can be either a normal function, or a template specialization. But crucially, it may not involve extra constructor calls that might confuse overload resolution. </li><li>Fix the intrusive code to not run unnecessary <code>const_cast_from</code> detection, i.e., when the argument is already a pointer to a non-const object. This is hard, because it's unclear where to look. </li><li>More robust <code>const_cast_from</code> detection. </li></ul> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Sat, 06 Dec 2014 19:09:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10853#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10853#comment:2</guid> <description> <p> const_cast_from must be a template because you can't only const_cast from a pointer to a const object but also from a non-const volatile object, const_cast also works for expressions that only remove volatile, etc. </p> <p> I agree that list::front() does not need to use const_cast_from but this expression: </p> <p> int *p = 0; const_cast&lt;int*&gt;(p); </p> <p> is valid, and const_cast_from tried to emulate all this permitted behaviour (specially to support some generic code where pointers passed as argumnets could be non-const-qualified. </p> </description> <category>Ticket</category> </item> <item> <author>Matei David <matei@…></author> <pubDate>Sun, 07 Dec 2014 23:37:45 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10853#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10853#comment:3</guid> <description> <p> The non-template conversion function I was using (in 5 above) could do <code>Ptr&lt;A&gt;</code> to <code>Ptr&lt;A&gt;</code> conversion by using an intermediate <code>Ptr&lt;const A&gt;</code> object. The problem was not with the conversion function not being general enough, but with the <code>pointer_traits</code> code failing while detecting the presence of <code>const_cast_from</code>, because it involved an extra constructor call. This extra constructor call confused the overload resolution. </p> <p> I don't mind <code>const_cast_from</code> being a template, what I minded was finding it out the hard way. Perhaps this could be better explained here: <a href="http://www.boost.org/doc/libs/1_57_0/doc/html/boost/intrusive/pointer_traits.html">http://www.boost.org/doc/libs/1_57_0/doc/html/boost/intrusive/pointer_traits.html</a> </p> <p> Here's a suggestion: </p> <p> When defining a custom family of pointers or references to be used with BI library, make sure the public static conversion functions accessed through the <code>pointer_traits</code> interface (<code>*_cast_from</code> and <code>pointer_to</code>) can properly convert between const and nonconst referred member types <span class="underline">without the use of implicit constructor calls</span>. It is suggested these conversions be implemented as function templates, where the template argument is the type of the object being converted from. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Mon, 15 Dec 2014 20:05:28 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/10853#comment:4 https://svn.boost.org/trac10/ticket/10853#comment:4 <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">fixed</span> </li> </ul> <p> I added your proposal to the pointer_traits documentation: </p> <p> SHA-1: 50f9f57f6cc3c6d4f8cfe1c5a2967e297ad487db </p> <ul><li>Documented pointer_traits according to Trac <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/10853" title="#10853: Bugs: problem with detection of const_cast_from (closed: fixed)">#10853</a> proposal </li></ul><p> Thanks. </p> Ticket