Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8919123
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 15, 20262026-06-15T05:56:13+00:00 2026-06-15T05:56:13+00:00

Expanding on this earlier post , I thought I would try to capture a

  • 0

Expanding on this earlier post, I thought I would try to capture a std::vector<boost::variant<double,std::string>> instead of just boost::variant<double,std::string>, but starting with the same-old-inputs first.

Here is my output given inputs ‘foo’ and 42.7:

/tmp$ g++ -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox 
<m_rule>
  <try>foo</try>
  <success></success>
  <attributes>[[f, o, o]]</attributes>
</m_rule>
<m_rule>
  <try>42.7</try>
  <success></success>
  <attributes>[42.7]</attributes>
</m_rule>
std::string='foo'
double='42.7'
/tmp$ g++ -g -std=c++11 -DDO_VECTOR sandbox.cpp -o sandbox && ./sandbox 
<m_rule>
  <try>foo</try>
  <success></success>
  <attributes>[[102, 111, 111]]</attributes>
</m_rule>
<m_rule>
  <try>42.7</try>
  <success></success>
  <attributes>[[42.7]]</attributes>
</m_rule>
double='111'
double='42.7'
/tmp$

For some reason that I don’t understand, the parser seems to be generating ASCII values for ‘foo’ and causing some confusion.

Do I need to change the parser when I turn on DO_VECTOR?

Should I be using a different container?

CODE

#define BOOST_SPIRIT_DEBUG

#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>

// #define DO_VECTOR

namespace {
namespace                              qi = boost::spirit::qi;
typedef   std::string::const_iterator  Iterator;

#ifdef DO_VECTOR
typedef std::vector<boost::variant<double, std::string>>  MY_TYPE;
#else
typedef boost::variant<double, std::string>               MY_TYPE;
#endif

class my_visitor
    : public boost::static_visitor<>
{
    public:
    my_visitor( std::string& result ) : m_str( result ) { }
    void operator()( double& operand )
    {
        std::ostringstream oss;
        oss << "double='" << operand << "'";
        m_str = oss.str();
    }
    void operator()( std::string& operand )
    {
        m_str = "std::string='";
        m_str.append( operand );
        m_str.append( "'" );
    }
    std::string& m_str;
};

// -----------------------------------------------------------------------------

struct variant_grammar : 
    qi::grammar<Iterator, MY_TYPE()>
{
    qi::rule<Iterator, MY_TYPE()> m_rule;

    variant_grammar() : variant_grammar::base_type(m_rule)
    {
        m_rule %= (qi::double_ | +qi::char_);

        BOOST_SPIRIT_DEBUG_NODE( m_rule );
    }
};

}

// -----------------------------------------------------------------------------

int main()
{
    const std::string    a( "foo" ), b( "42.7" );
    variant_grammar      varGrammar;

    MY_TYPE varA, varB;
    auto begA = a.begin(), endA = a.end();
    auto begB = b.begin(), endB = b.end();
    qi::parse( begA, endA, varGrammar, varA );
    qi::parse( begB, endB, varGrammar, varB );

    if ( begA!=endA )
        std::cerr << "A FAILED TO COMPLETELY PARSE" << std::endl;
    if ( begB!=endB )
        std::cerr << "B FAILED TO COMPLETELY PARSE" << std::endl;

    std::string resultA, resultB;
    my_visitor visitor1( resultA );
    my_visitor visitor2( resultB );

#ifdef DO_VECTOR
    std::for_each( varA.begin(), varA.end(), boost::apply_visitor( visitor1 ));
    std::for_each( varB.begin(), varB.end(), boost::apply_visitor( visitor2 ));
#else
    boost::apply_visitor( visitor1, varA );
    boost::apply_visitor( visitor2, varB );
#endif

    std::cout << resultA << std::endl;
    std::cout << resultB << std::endl;

    return 0;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-15T05:56:14+00:00Added an answer on June 15, 2026 at 5:56 am

    Another solution is using qi::as_string[].

    struct variant_grammar : 
        qi::grammar<Iterator, MY_TYPE()>
    {
        qi::rule<Iterator, MY_TYPE()> m_rule;
    
        variant_grammar() : variant_grammar::base_type(m_rule)
        {
            m_rule %= (qi::double_ | qi::as_string[+qi::char_]);
    
            BOOST_SPIRIT_DEBUG_NODE( m_rule );
        }
    };
    

    Let’s forget for a moment about the double. Your rule has an attribute of std::vector<std::string> that simplified is vector<vector<char>> and your +qi::char_ has an attribute vector<char>. What you want for “foo” is a vector1<vector3<char>> and what you get is a vector3<vector1<char>>. This is explained in the link above: when you have a situation like this, +qi::char calls traits::push_back_container for every char it parses. You can either use an auxiliary rule, as in sharth’s answer, to disambiguate the situation or you can use one of the atomic parsing directives (qi::as_string[] in this case).

    Edit:

    Here is the code that solves your new problem:

    #define BOOST_SPIRIT_DEBUG
    
    #include <boost/spirit/include/qi.hpp>
    #include <boost/variant.hpp>
    
    // #define DO_VECTOR
    
    namespace {
    namespace                              qi = boost::spirit::qi;
    typedef   std::string::const_iterator  Iterator;
    
    #ifdef DO_VECTOR
    typedef std::vector<boost::variant<double, std::string>>  MY_TYPE;
    #else
    typedef boost::variant<double, std::string>               MY_TYPE;
    #endif
    
    class my_visitor
        : public boost::static_visitor<>
    {
        public:
        my_visitor( std::string& result ) : m_str( result ) { }
        void operator()( double& operand )
        {
            std::ostringstream oss;
            oss << "double='" << operand << "'";
            m_str += oss.str();
        }
        void operator()( std::string& operand )
        {
            m_str += "std::string='";
            m_str.append( operand );
            m_str.append( "'" );
        }
        std::string& m_str;
    };
    
    // -----------------------------------------------------------------------------
    
    struct variant_grammar : 
        qi::grammar<Iterator, MY_TYPE(), qi::space_type> //added a skipper to the grammar
    {
        qi::rule<Iterator, MY_TYPE(), qi::space_type> m_rule; //and to the rule. It's specially important that the starting rule and your grammar have the exact same template parameters
    
        variant_grammar() : variant_grammar::base_type(m_rule)
        {
            m_rule %= +(qi::double_ | qi::as_string[+(qi::char_-qi::digit)]);//Limited the string parser and added a `+` in order to parse more than one element
    
            BOOST_SPIRIT_DEBUG_NODE( m_rule );
        }
    };
    
    }
    
    // -----------------------------------------------------------------------------
    
    int main()
    {
        const std::string    a( "foo 4.9 bar" ), b( "42.7" );
        variant_grammar      varGrammar;
    
        MY_TYPE varA, varB;
        auto begA = a.begin(), endA = a.end();
        auto begB = b.begin(), endB = b.end();
        qi::phrase_parse( begA, endA, varGrammar, qi::space, varA ); //when you have a skipper in your rule/grammar you need to use phrase_parse
        qi::phrase_parse( begB, endB, varGrammar, qi::space, varB );
    
        if ( begA!=endA )
            std::cerr << "A FAILED TO COMPLETELY PARSE" << std::endl;
        if ( begB!=endB )
            std::cerr << "B FAILED TO COMPLETELY PARSE" << std::endl;
    
        std::string resultA, resultB;
        my_visitor visitor1( resultA );
        my_visitor visitor2( resultB );
    
    #ifdef DO_VECTOR
        std::for_each( varA.begin(), varA.end(), boost::apply_visitor( visitor1 ));
        std::for_each( varB.begin(), varB.end(), boost::apply_visitor( visitor2 ));
    #else
        boost::apply_visitor( visitor1, varA );
        boost::apply_visitor( visitor2, varB );
    #endif
    
        std::cout << resultA << std::endl;
        std::cout << resultB << std::endl;
    
        return 0;
    }
    

    Several small changes: added a skipper to the grammar and used phrase_parse instead of parse consequently. Limited the string parser. Changed the printers to append to your string not overwrite it.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Expanding on Jon Skeet's answer to This Previous Question . Skeet doesn't address the
Expanding on this question , it looks like I did not provide enough detail.
Background Expanding upon this question. I have a collection of points (in a three
noob to git: expanding on this question a little I created a repository and
This question is expanding on another I had gotten help with via Stackoverflow (
I am expanding forms that are created with Zend_Dojo , for this i have
Doing this in a console program: object x = new string(new char[0]); If one
I'm expanding further on this question . I currently have an asp.net hyperlink for
Expanding on a question I asked earlier about how to iterate over a collection
Considering that the family of iDevices is expanding, I guess this is a problem

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.