Boost C++ Libraries: Ticket #9742: for_each causes funny behavior in phoenix V3 expressions https://svn.boost.org/trac10/ticket/9742 <p> Using phoenix::for_each in a Phoenix expression produces a strange behavior, which seems to be reverse execution of the comma-separated expressions. This does NOT happen when you include Phoenix V2 from the spirit directory. </p> <p> Sample Code: (Full code attached) </p> <pre class="wiki">std::vector&lt;int&gt; v{1,2}; (std::cout &lt;&lt; phx::val("("), phx::for_each(arg1, phx::lambda[std::cout &lt;&lt; arg1]), std::cout &lt;&lt; phx::val(")"))(v); </pre><p> This originally showed up for me when using phoenix expressions in spirit semantic actions, discussed here: <a class="ext-link" href="http://boost.2283326.n4.nabble.com/Phoenix-V3-for-each-or-lambda-seem-to-be-ruining-qi-semantic-actions-tp4659691.html"><span class="icon">​</span>http://boost.2283326.n4.nabble.com/Phoenix-V3-for-each-or-lambda-seem-to-be-ruining-qi-semantic-actions-tp4659691.html</a> </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/9742 Trac 1.4.3 Chromatix <mhazadmanesh2009@…> Wed, 05 Mar 2014 08:07:20 GMT attachment set https://svn.boost.org/trac10/ticket/9742 https://svn.boost.org/trac10/ticket/9742 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">boostphxtest.cpp</span> </li> </ul> Ticket John Fletcher <J.P.Fletcher@…> Mon, 10 Mar 2014 16:53:20 GMT <link>https://svn.boost.org/trac10/ticket/9742#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:1</guid> <description> <p> Hi. Note I have taken on maintenance of Phoenix but the Trac system does not have that information yet. I have observed this myself and there are some problems with the comma operator in 1.55.0 and earlier. I will try your test against the current development which has some fixes. Some will be in 1.56.0 when it comes out. I had seen similar things myself before I became maintainer. John </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Mon, 10 Mar 2014 22:17:51 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:2</guid> <description> <p> I have run your test with my latest develop version and unfortunately the bug is still there. It is compiler dependent. gcc 4.6 and 4.8.2 give bad results and clang 3.4 gives correct on Ubuntu Linux. I do not have a work around for it on the failing compilers. John </p> </description> <category>Ticket</category> </item> <item> <author>Chromatix <mhazadmanesh2009@…></author> <pubDate>Thu, 13 Mar 2014 20:47:48 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:3</guid> <description> <p> Hello. </p> <p> Sorry I forgot to mention my original code that failed (and the attached file) was tested on MSVC 2010. </p> <p> Thanks for taking care btw. </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Sun, 16 Mar 2014 10:19:11 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:4</guid> <description> <p> With further testing I have shown that the following code does NOT show the error with gcc 4.6 and gcc 4.8.2. Clang 3.4 also works. </p> <pre class="wiki">#include &lt;sstream&gt; std::ostringstream out; ( out &lt;&lt; phx::val("("), phx::for_each(arg1, phx::lambda[out &lt;&lt; arg1]), out &lt;&lt; phx::val(")") )(v); std::cout &lt;&lt; out.str() &lt;&lt; std::endl; </pre><p> I don't have an explanation for why it doesn't work with <code>std::cout</code>. Would you please test with MSVC and see if this works for that as well. </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Sun, 16 Mar 2014 11:37:59 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:5</guid> <description> <p> Sorry, my mistake, the code above still does not work with gcc 4.6 and 4.8.2 </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Sun, 16 Mar 2014 18:58:13 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:6</guid> <description> <p> I have done some more experiments. The following code, using for_ in place of for_each does work for the compilers I have tested: </p> <pre class="wiki"> int iii; int size = v.size(); ( std::cout &lt;&lt; phx::val("("), phx::for_(phx::ref(iii) = 0, phx::ref(iii) &lt; size, ++phx::ref(iii) ) [std::cout &lt;&lt; arg1[phx::ref(iii)] ], std::cout &lt;&lt; phx::val(")") )(v); </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Mon, 17 Mar 2014 03:38:07 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:7</guid> <description> <p> that workaround does not fix the problem. have you tried wrapping out in a ref or cref? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Mon, 17 Mar 2014 03:39:05 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:8</guid> <description> <p> that last comment is from me, btw. </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Mon, 24 Mar 2014 13:21:02 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:9</guid> <description> <p> I am no nearer to solving this. I have put two new tests onto Phoenix develop - for_test and for_each in the hope of finding the failures. However, the tests pass on all compilers, even gcc 4.6 and 4.8.2 where my own tests fail. I must be missing something. John. </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Wed, 02 Apr 2014 19:59:58 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:10</guid> <description> <p> I think I now have a reason for this. The implementation of phoenix::for_each is located in <code>boost/phoenix/stl/algorithm/iteration.hpp</code>. The actual code is this: </p> <pre class="wiki"> template&lt;class R, class F&gt; F const operator()(R&amp; r, F const&amp; fn) const { return std::for_each(detail::begin_(r), detail::end_(r), fn); } </pre><p> The "C++ Standard Library" N.M.Josuttis p.300 explains the rationale for a return type from for_each. However in this case replacing the code by </p> <pre class="wiki"> template&lt;class R, class F&gt; F const operator()(R&amp; r, F const&amp; fn) const { std::for_each(detail::begin_(r), detail::end_(r), fn); } </pre><p> and making the return type void to code works. I think the return object is a temporary which is getting discarded and invalidating the return mechanism in the comma operator. I will discuss this with the other maintainers. </p> </description> <category>Ticket</category> </item> <item> <author>Chromatix <mhazadmanesh2009@…></author> <pubDate>Wed, 02 Apr 2014 21:51:01 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:11</guid> <description> <p> Erm, in the mailing list thread whose link is in the initial post, TONGARI J already suggested that changing the return type to <code>void</code> works and yes it does on VC 2010; I didn't know if you saw it and was unsure if I had to bring this up sooner, sorry. </p> <p> &lt; useless novice thoughts &gt; </p> <p> After reading the rationale, it seems <code>for_each</code>'s return value might be useful in some cases, and removing it may cause inconsistency between the original and lazy version of the <code>for_each</code>. Phoenix V2's <code>for_each</code> <strong>does</strong> return <code>std::foreach</code>'s return value but this problem doesn't exist there. </p> <p> By the way, does adding <em>another layer of laziness</em> to the return value help? e.g wrapping the functor returned by <code>std::for_each</code> inside another functor class and returning that one from <code>phoenix::for_each</code>, or returning a <code>phoenix::(c)ref</code> of <code>std::for_each</code>'s return value, or returning <code>phoenix::bind</code> of <code>std::for_each</code>'s return value, or maybe by wrapping <code>std::for_each</code>'s return value in some proto tags. Due to lack of knowledge, I wasn't successful in implementing any of the above thoughts and testing them (got massive template errors). </p> <p> &lt;/ useless novice thoughts &gt; </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Wed, 02 Apr 2014 22:21:26 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:12</guid> <description> <p> Thank you. I was just reading the mailing list thread and saw it had suggested returning void. I arrived at my conclusions by working with the phoenix example code 'container_actor' and comparing a size_impl functor which works with the for_each code. I have looked into what is happening at the Proto level, and the code in the bracket is passed to a set of comma operators. There is a Proto operation called display_expr() which makes this clear. The ones containing the return object from for_each get wrongly processed, that is if it is (a,b) then b gets processed before a, but only by some compilers and only sometimes. My tests on develop work when I don't expect them to. Changing to the void return removes the problem. I need to explore why this happens with the other developers. </p> <p> When I have implemented a solution I will post it here. I want to make the return object available for cases where it is needed. </p> <p> Would you let me know what other cases fail? I think you said that there were problems with my for_ solution but I cannot reproduce those with gcc on Linux. </p> <p> Thank you. </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Wed, 02 Apr 2014 22:36:00 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:13</guid> <description> <p> Can you check out using phoenix::accumulate() which in my testing works O.K.? It does return a value. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Eric Niebler</dc:creator> <pubDate>Wed, 02 Apr 2014 23:30:23 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:14</guid> <description> <p> It has something to do with the <code>phx::lambda</code>. The following does *not* exhibit the problem: </p> <pre class="wiki">std::vector&lt;int&gt; v{1,2}; boost::function&lt;void(int)&gt; fun = std::cout &lt;&lt; arg1; ( std::cout &lt;&lt; phx::val("("), phx::for_each(arg1, fun), std::cout &lt;&lt; phx::val(")") )(v); </pre><p> I'd start by looking at what is special about phx expressions that have lambdas. Some transform is getting applied that is doing the wrong thing for comma operators or binary operators that are left-associative. </p> </description> <category>Ticket</category> </item> <item> <author>John Fletcher <J.P.Fletcher@…></author> <pubDate>Mon, 07 Apr 2014 16:43:57 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9742#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9742#comment:15</guid> <description> <p> This case also does not appear to have the problem: </p> <pre class="wiki">std::vector&lt;int&gt; v{1,2}; boost::function&lt;void(int)&gt; phxlam = phx::lambda[std::cout &lt;&lt; arg1](); ( std::cout &lt;&lt; phx::val("("), phx::for_each(arg1, phxlam) , std::cout &lt;&lt; phx::val(")") )(v); </pre><p> Note the () after the definition of the lambda. The problem seems to occur when the return from the for_each is a lambda_actor object. </p> </description> <category>Ticket</category> </item> </channel> </rss>