Boost C++ Libraries: Ticket #4540: fold<Sequence>() instantiates result_of::fold<Sequence const> https://svn.boost.org/trac10/ticket/4540 <p> Hi, </p> <p> this is a complicated one, I'll try my best: </p> <p> there is a problem with fold() and maybe other fusion functions whose result is computed from the result type of user functors. </p> <p> in iteration/detail/fold.hpp, there are two fold()'s, the default one and a specialization for const sequences: </p> <pre class="wiki"> inline typename result_of::fold&lt;Seq const,State const,F&gt;::type BOOST_FUSION_FOLD_NAME(Seq const&amp; seq,State const&amp; state,F f) </pre><p> I'm not sure why it is there since there isn't any difference to the non-const fold(). but the fact that it is there causes problems when using fold() with a non-const sequence: </p> <pre class="wiki"> fusion::vector&lt;int&gt; vec; fusion::fold(vec,0,F()); </pre><p> even though the sequence is not const, at least MSVC (and I vaguely remember something about that in the C++ standard) instantiates all result types of the function overload set, before the arguments are matched to the non-const fold(). </p> <p> ==&gt; fusion::result_of::fold&lt;Sequence <strong>const</strong>,State,F&gt; is instantiated. </p> <p> under normal circumstances this only constitutes an unnecessary instantiation, but when the result type depends on user functors it can cause instantiatiation of undefined types. </p> <p> for example: </p> <pre class="wiki">struct F{ template&lt;typename Args&gt; struct result; int operator()(int state,int &amp;element) const{ return state; } }; template&lt;typename State&gt; struct F::result&lt;F(State,int &amp;)&gt;{ typedef int type; }; int main(){ fusion::vector&lt;int&gt; vec; fusion::fold(vec,0,F()); } </pre><p> the result type of F is only defined for argument type "int &amp;", which is enough for this fold. but the call to fold() instantiates the <em>const</em> specialization of fold(), and therefore instantiates result_of::fold&lt;vector <strong>const</strong>&gt;, which instantiates the result type of F(State,int const &amp;) ==&gt; compiler error </p> <p> when the following code snippet is added as a workaround, it works: </p> <pre class="wiki">template&lt;typename State&gt; struct F::result&lt;F(State,int const &amp;)&gt;{ typedef int type; }; </pre><p> bottom line - the const specialization of fold() probably shouldn't be there. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/4540 Trac 1.4.3 Steven Watanabe Fri, 13 Aug 2010 18:12:15 GMT <link>https://svn.boost.org/trac10/ticket/4540#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4540#comment:1</guid> <description> <p> The const overload is necessary to catch non-const rvalues. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 13 Aug 2010 18:40:10 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4540#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4540#comment:2</guid> <description> <p> I see. but I guess there is another solution, because the following works: </p> <pre class="wiki"> struct A{}; template&lt;typename T&gt; struct fresult; template&lt;&gt; struct fresult&lt;A&gt;{ typedef void type; }; template&lt;typename T&gt; typename fresult&lt;T&gt;::type f(T &amp;){} template&lt;typename T&gt; typename fresult&lt;T const&gt;::type f(T const &amp;){} int main(){ A a; f(a); } </pre><p> the undefined fresult&lt;T const&gt; is not instantiated for the call to the non-const overload. I don't know what exactly causes the instantiation of result_of::fold&lt;Seq const&gt;, but this suggests there might a solution other than removing the const overload. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Christopher Schmidt</dc:creator> <pubDate>Tue, 17 Aug 2010 22:53:06 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/4540#comment:3 https://svn.boost.org/trac10/ticket/4540#comment:3 <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> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/4540#comment:2" title="Comment 2">anonymous</a>: </p> <blockquote class="citation"> <p> I see. but I guess there is another solution, because the following works: </p> <pre class="wiki"> struct A{}; template&lt;typename T&gt; struct fresult; template&lt;&gt; struct fresult&lt;A&gt;{ typedef void type; }; template&lt;typename T&gt; typename fresult&lt;T&gt;::type f(T &amp;){} template&lt;typename T&gt; typename fresult&lt;T const&gt;::type f(T const &amp;){} int main(){ A a; f(a); } </pre><p> the undefined fresult&lt;T const&gt; is not instantiated for the call to the non-const overload. I don't know what exactly causes the instantiation of result_of::fold&lt;Seq const&gt;, but this suggests there might a solution other than removing the const overload. </p> </blockquote> <p> That sample compiles fine as SFINAE is taking care of the non-existing specialization. SFINAE does not help in your fusion usecase, though. There is simply no specialization of F::result that matches the template arguments in the first place - and that very instantiation is directly referenced by the boost::result_of implementation. I do not think that this issue can be worked-around. </p> <p> Here is a minimal non-fusion testcase. </p> <pre class="wiki">#include &lt;boost/utility/result_of.hpp&gt; struct A{}; struct F { template&lt;typename&gt; struct result; template&lt;typename Self&gt;struct F::result&lt;Self(A&amp;)&gt; {typedef void type;}; #if 0 template&lt;typename Self&gt;struct F::result&lt;Self(A const&amp;)&gt; {typedef void type;}; #endif }; template&lt;typename C&gt; typename boost::result_of&lt;F(C const&amp;)&gt;::type bub(C const&amp;){} template&lt;typename C&gt; typename boost::result_of&lt;F(C&amp;)&gt;::type bub(C&amp;){} int main() { A a; bub(a); } </pre> Ticket anonymous Wed, 18 Aug 2010 08:58:39 GMT status changed; resolution deleted https://svn.boost.org/trac10/ticket/4540#comment:4 https://svn.boost.org/trac10/ticket/4540#comment:4 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">wontfix</span> </li> </ul> <p> reopening this ticket for now, as I think it can be fixed, even though "component" might have to be changed: </p> <pre class="wiki"> BOOST_MPL_HAS_XXX_TRAIT_DEF(type) struct invalid; template&lt;typename F,typename Args&gt; struct result_of_impl{ typedef typename boost::mpl::eval_if&lt; has_type&lt;typename F::template result&lt;Args&gt; &gt;, typename F::template result&lt;Args&gt;, boost::mpl::identity&lt;invalid&gt; &gt;::type type; }; </pre><p> with this fix to result_of your code above yields these results: </p> <pre class="wiki"> A a; bub(a); //ok bub(A()); //error: use of undefined type "invalid" </pre><p> do you see any problems with this? "invalid" could be further extended to give a meaningful error message, e.g. undefined_result_type&lt;FArgs&gt; </p> Ticket Christopher Schmidt Wed, 18 Aug 2010 16:49:13 GMT type, component changed https://svn.boost.org/trac10/ticket/4540#comment:5 https://svn.boost.org/trac10/ticket/4540#comment:5 <ul> <li><strong>type</strong> <span class="trac-field-old">Bugs</span> → <span class="trac-field-new">Feature Requests</span> </li> <li><strong>component</strong> <span class="trac-field-old">fusion</span> → <span class="trac-field-new">utility</span> </li> </ul> <p> Well, I am not sure about that. Anyway, lets change the component to utility. </p> <p> BTW. the upcoming c++11 port solves this issue by implementing fold as </p> <pre class="wiki">template&lt;typename Seq, ...&gt; typename result_of::fold&lt;...&gt;::type fold(Seq&amp;&amp;, ...) </pre> Ticket Christopher Schmidt Wed, 18 Aug 2010 16:51:15 GMT owner, status changed; cc set https://svn.boost.org/trac10/ticket/4540#comment:6 https://svn.boost.org/trac10/ticket/4540#comment:6 <ul> <li><strong>cc</strong> <span class="trac-author">mr.chr.schmidt@…</span> added </li> <li><strong>owner</strong> changed from <span class="trac-author">Joel de Guzman</span> to <span class="trac-author">Douglas Gregor</span> </li> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">new</span> </li> </ul> Ticket viboes Sat, 13 Apr 2013 16:50:35 GMT component changed https://svn.boost.org/trac10/ticket/4540#comment:7 https://svn.boost.org/trac10/ticket/4540#comment:7 <ul> <li><strong>component</strong> <span class="trac-field-old">utility</span> → <span class="trac-field-new">result_of</span> </li> </ul> Ticket