Boost C++ Libraries: Ticket #3270: Ambiguous conversion, even though no conversion exists https://svn.boost.org/trac10/ticket/3270 <p> Cheers from Germany! </p> <p> Look at the following code: </p> <pre class="wiki">#include &lt;boost/function.hpp&gt; struct A {}; struct B { void f(const A &amp;a) const {} void f(boost::function&lt; void () &gt; a) {} }; int main() { A a; B b; b.f(a); } </pre><p> Compiling this, I get the error: </p> <pre class="wiki">&gt; g++ boosttest.cpp -o boosttest boosttest.cpp: In function ‘int main()’: boosttest.cpp:13: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: boosttest.cpp:6: note: candidate 1: void B::f(const A&amp;) const boosttest.cpp:7: note: candidate 2: void B::f(boost::function&lt;void ()(), std::allocator&lt;void&gt; &gt;) </pre><p> When I define B::f() in the first version non-const, the program compiles without any problems. Usually, the problem in these cases is, that the conversion from an A to a const A object is seen as an operation as bad as the conversion of the object to another, therefore it is ambiguous and can be healed by using "explicit" in the conversion operator of the other class. Unfortunately, in this case, there does not even exist a conversion from "class A" to the function type! To test that, just comment the first definition of B::f(): </p> <pre class="wiki"> f(const A &amp;a) const {} </pre><p> compilation fails with: </p> <pre class="wiki">&gt; g++ boosttest.cpp -o boosttest [clip] boosttest.cpp:13: instantiated from here /usr/include/boost/function/function_template.hpp:136: error: no match for call to ‘(A) ()’ </pre><p> I think that this can be considered a bug. Or what else can I do in this case? </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3270 Trac 1.4.3 Steven Watanabe Fri, 17 Jul 2009 16:20:55 GMT <link>https://svn.boost.org/trac10/ticket/3270#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3270#comment:1</guid> <description> <p> Replying to <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3270" title="#3270: Bugs: Ambiguous conversion, even though no conversion exists (closed: invalid)">Olaf Lenz &lt;lenzo@…&gt;</a>: </p> <blockquote class="citation"> <p> Unfortunately, in this case, there does not even exist a conversion from "class A" to the function type! To test that, just comment the first definition of B::f(): </p> </blockquote> <p> Any type can be converted to a boost::function. The declaration of the conversion always exists, which is all that the compiler checks for in overload resolution. The conversion doesn't compile unless the type has a function call operator. </p> <blockquote class="citation"> <p> I think that this can be considered a bug. Or what else can I do in this case? </p> </blockquote> <p> Did you really intend to make the overload for A const and the overload for boost::function non-const? </p> <p> The following compiles for me </p> <pre class="wiki">#include &lt;boost/function.hpp&gt; struct A {}; struct B { void f(const A &amp;a) const {} void f(boost::function&lt; void () &gt; a) const {} }; int main() { A a; B b; b.f(a); } </pre> </description> <category>Ticket</category> </item> <item> <author>lenzo@…</author> <pubDate>Sat, 18 Jul 2009 10:37:40 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3270#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3270#comment:2</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/3270#comment:1" title="Comment 1">steven_watanabe</a>: </p> <blockquote class="citation"> <p> Any type can be converted to a boost::function. The declaration of the conversion always exists, which is all that the compiler checks for in overload resolution. The conversion doesn't compile unless the type has a function call operator. </p> </blockquote> <p> That is a pity. Then I guess there is no way to make it work. </p> <blockquote class="citation"> <blockquote class="citation"> <p> I think that this can be considered a bug. Or what else can I do in this case? </p> </blockquote> <p> Did you really intend to make the overload for A const and the overload for boost::function non-const? </p> </blockquote> <p> Indeed, that is what I wanted. Probably I should introduce the actual application: I'm having a (self-written) container class "Set", which provides internal iterators, i.e. a method "foreach", which is overloaded in several ways. Here, T is the type of the contained objects. </p> <pre class="wiki">class Set { virtual foreach(boost:function&lt; void (T) &gt;); virtual foreach(boost:function&lt; void (const T) &gt;) const ; virtual foreach(Computer); virtual foreach(ConstComputer) const; } </pre><p> where Computer and <a class="missing wiki">ConstComputer</a> are defined as follows: </p> <pre class="wiki">class Computer { virtual void prepare(); virtual void apply(T); virtual void finalize(); } class ConstComputer { virtual void prepare(); virtual void apply(const T); virtual void finalize(); } </pre><p> The idea is that it is possible to use foreach with an arbitrary function, or with an object of type "Computer", which provides the methods prepare() and finalize() to be called before and after the loop. To be able to loop over a constant container of constant objects, it would be nice to be able to use a <a class="missing wiki">ConstComputer</a>. Unfortunately, this is where the code fails. Also, it looks as though there is no way round it other than to use two functions. Or is there? </p> <p> Best regards </p> <blockquote> <p> Olaf </p> </blockquote> </description> <category>Ticket</category> </item> <item> <dc:creator>Steven Watanabe</dc:creator> <pubDate>Sat, 18 Jul 2009 15:53:39 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3270#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3270#comment:3</guid> <description> <p> Then the easiest solution is to add </p> <pre class="wiki">void foreach(ConstComputer&amp; c) { return(static_cast&lt;const Set*&gt;(this)-&gt;foreach(c)); } </pre> </description> <category>Ticket</category> </item> <item> <author>lenzo@…</author> <pubDate>Tue, 21 Jul 2009 11:43:09 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3270#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3270#comment:4</guid> <description> <p> Ok, yes, this seems to work. Thanks for the hint. </p> <p> I'm not exactly sure what to do about this ticket now. It seems to be not exactly a bug in boost.function, but more of a generic C++ problem. Is it even a problem in the C++ standard? I mean, it is surely not a Good Thing (tm) if C++-code does not compile even though there would be a perfectly valid solution, only because the compiler cannot identify it. </p> <p> I must, however, admit, that I am currently not able to pinpoint the precise problem: why does the compiler first think that there is a conversion from any object to a boost.function object, and only later notice that it cannot call the object? </p> <p> Do you have any suggestions how to proceed? Or shall we just close this issue as invalid or wontfix? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Steven Watanabe</dc:creator> <pubDate>Fri, 21 Aug 2009 21:15:12 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/3270#comment:5 https://svn.boost.org/trac10/ticket/3270#comment:5 <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">invalid</span> </li> </ul> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/3270#comment:4" title="Comment 4">lenzo@…</a>: </p> <blockquote class="citation"> <p> I must, however, admit, that I am currently not able to pinpoint the precise problem: why does the compiler first think that there is a conversion from any object to a boost.function object, and only later notice that it cannot call the object? </p> </blockquote> <p> That's just the way C++ works. The compiler only checks the declaration (which is correct), not the definition. </p> Ticket