Boost C++ Libraries: Ticket #12094: Operator > changes attribute type https://svn.boost.org/trac10/ticket/12094 <p> Following code should compile, but it does not. </p> <pre class="wiki">#include &lt;boost/spirit/home/x3.hpp&gt; #include &lt;string&gt; using namespace boost::spirit::x3; auto r = rule&lt;class r, std::string&gt;{} = +char_; int main() { std::string input = ""; std::string output; auto b = std::begin(input); auto e = std::end(input); parse(b, e, 'a' &gt; (r | r), output); } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12094 Trac 1.4.3 Joel de Guzman Thu, 24 Mar 2016 10:33:22 GMT <link>https://svn.boost.org/trac10/ticket/12094#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:1</guid> <description> <p> It may be unintuitive, but it is not really a bug. Sequences (including expect operators in x3) may accept a tuple or container (e.g. string). If it gets a container, it expects its nodes to have an attribute of either a container, or the container's value type. See <a href="http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc/html/spirit/qi/reference/operator/sequence.html">http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc/html/spirit/qi/reference/operator/sequence.html</a> </p> <p> But what is the natural (inherent) attribute type of (r | r)? It is a variant, not a container. That is why X3 got tripped. It can't handle the ambiguity. X3's attribute handling mechanism is not perfect. As it descends into the alternative, it already decided that its attribute cannot handle the container, and thus tries to pass the element type of the container. </p> <p> Tip: Don't fight the attribute mechanism. Try to form your attributes as closely as possible to the rules and grammars that models it. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Thu, 24 Mar 2016 10:33:42 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/12094#comment:2 https://svn.boost.org/trac10/ticket/12094#comment:2 <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> Ticket mikhail.strelnikov@… Thu, 24 Mar 2016 12:28:53 GMT <link>https://svn.boost.org/trac10/ticket/12094#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:3</guid> <description> <p> Why 'a' &gt;&gt; (r | r) compiles then? :-) </p> <p> I'd expect attr of (r | r) to be std::string because attr of r is std::string, why it should be variant? </p> </description> <category>Ticket</category> </item> <item> <author>mikhail.strelnikov@…</author> <pubDate>Thu, 24 Mar 2016 12:55:01 GMT</pubDate> <title>status changed; resolution deleted https://svn.boost.org/trac10/ticket/12094#comment:4 https://svn.boost.org/trac10/ticket/12094#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> Sorry, I had to reopen this issue - not sure if commenting on closed issues does anything. </p> <p> 'a' &gt;&gt; (r | r) - compiles, attr is std::string<br /> </p> <p> *('a' &gt;&gt; (r | r)) - compiles, attr is std::string<br /> </p> <p> <br /> <br /> </p> <p> 'a' &gt; (r | r) - does not compile<br /> </p> <p> *('a' &gt; (r | r)) - attr is std::vector&lt;std::string&gt;. Wat?<br /> </p> Ticket Joel de Guzman Thu, 24 Mar 2016 13:08:54 GMT <link>https://svn.boost.org/trac10/ticket/12094#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:5</guid> <description> <p> Hmmm... Does 'a' &gt;&gt; (r | r) give you the correct behavior? It's not enough that it compiles. </p> </description> <category>Ticket</category> </item> <item> <author>mikhail.strelnikov@…</author> <pubDate>Thu, 24 Mar 2016 13:50:46 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:6</guid> <description> <p> Yes, it works as expected <a class="ext-link" href="http://melpon.org/wandbox/permlink/htuj4CIXodD02pSb"><span class="icon">​</span>http://melpon.org/wandbox/permlink/htuj4CIXodD02pSb</a> (skips character 'a', stores 'b'). I don't quite see why it shouldn't. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Thu, 24 Mar 2016 16:04:00 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:7</guid> <description> <p> I see that now and I know the reason why: I made some special treatment for alternatives. Alas the special case handling does not apply for expect_directive&lt;alternative&gt;, or whatever else that might hold an alternative. I'm not sure if I should 'fix' this. But that special case becomes a precedent indeed ;-/ </p> <p> In any case, allow me to repeat myself again: don't fight the attribute mechanism. Try to form your attributes as closely as possible to the rules and grammars that models it. </p> </description> <category>Ticket</category> </item> <item> <author>mikhail.strelnikov@…</author> <pubDate>Thu, 24 Mar 2016 17:30:29 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:8</guid> <description> <p> So, I could write ('a' &gt;&gt; expect[r | r]) instead? Does not compile, but now it is as expected. :-) </p> <p> About "don't fight": </p> <pre class="wiki">std::string input = "\\n\\t\\u1234"; ... parse(b, e, *('\\' &gt; (escape_seq | unicode)), ...); </pre><p> What type of attribute it should return? It can be std::vector&lt;boost::variant&lt;esc_ast, unicode_ast&gt;&gt; (where esc_ast and unicode_ast are inheriting from x3::position_tagged because you need this) or in can be simple std::string. I think you can't tell the attribute type just by looking at the rule. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Thu, 24 Mar 2016 21:35:15 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:9</guid> <description> <p> So you say "Does not compile, but now it is as expected. :-)". Actually, this: </p> <pre class="wiki"> 'a' &gt; (r | r) </pre><p> is the same as this: </p> <pre class="wiki"> 'a' &gt;&gt; expect[r | r] </pre><p> But you say that the first is not expected and the second is expected. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Thu, 24 Mar 2016 21:43:48 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:10</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12094#comment:8" title="Comment 8">mikhail.strelnikov@…</a>: </p> <blockquote class="citation"> <p> About "don't fight": </p> <pre class="wiki">std::string input = "\\n\\t\\u1234"; ... parse(b, e, *('\\' &gt; (escape_seq | unicode)), ...); </pre><p> What type of attribute it should return? It can be std::vector&lt;boost::variant&lt;esc_ast, unicode_ast&gt;&gt; (where esc_ast and unicode_ast are inheriting from x3::position_tagged because you need this) or in can be simple std::string. I think you can't tell the attribute type just by looking at the rule. </p> </blockquote> <p> If esc_ast, unicode_ast can both be a string, then the natural attribute would be vector&lt;std::string&gt;. An attribute of std::string is just pushing it. </p> </description> <category>Ticket</category> </item> <item> <author>mikhail.strelnikov@…</author> <pubDate>Fri, 25 Mar 2016 16:35:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:11</guid> <description> <p> Why this works? </p> <pre class="wiki">#include &lt;boost/spirit/home/x3.hpp&gt; #include &lt;string&gt; using namespace boost::spirit::x3; auto r = rule&lt;class r, std::string&gt;{} = +char_; auto r_or_r = rule&lt;class r, std::string&gt;{} = r | r; auto expect_r_or_r = rule&lt;class r, std::string&gt;{} = expect[r_or_r]; auto a_expect_r_or_r = rule&lt;class r, std::string&gt;{} = 'a' &gt; expect_r_or_r; int main() { std::string input = "a"; std::string output; auto b = std::begin(input); auto e = std::end(input); parse(b, e, a_expect_r_or_r, output); } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Fri, 25 Mar 2016 22:07:24 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:12</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12094#comment:11" title="Comment 11">mikhail.strelnikov@…</a>: </p> <blockquote class="citation"> <p> Why this works? </p> </blockquote> <p> [snip] </p> <p> Why? Because you placed it in a rule with an exact attribute. Spirit does not have to deduce (guess) what you want. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Sat, 26 Mar 2016 01:17:33 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:13</guid> <description> <p> OK, alright, I pushed a "fix" for this issue. The reason I did it anyway, despite my comments above, is that the special case handling for alternatives became a precedent and it would be unwise not to give the expect operator another spacial treatment due to the implicit nature of the expression: </p> <pre class="wiki">a &gt; (b | c) </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Sat, 26 Mar 2016 01:17:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12094#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12094#comment:14</guid> <description> <p> Please try the Boost develop branch. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Sat, 26 Mar 2016 01:19:00 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/12094#comment:15 https://svn.boost.org/trac10/ticket/12094#comment:15 <ul> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Oh and BTW, thanks for your persistence! I really appreciate it. </p> Ticket