c++ - 从灵气中制作共享指针的 vector

标签 c++ shared-ptr boost-spirit boost-spirit-qi

这是来自 a previous question 的后续问题.

我可以从语法中解析为字符串 vector ,但我似乎无法解析为字符串共享指针的 vector ;即 std::vector<std::shared_ptr<std::string> > ,需要一点帮助。

我的编译头文件:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1


#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>


#include <boost/spirit/include/phoenix_stl.hpp>

#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>



// this solution for lazy make shared comes from the SO forum, user sehe.
// https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared
//    post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
    template <typename T>
    struct make_shared_f
    {
        template <typename... A> struct result
        { typedef std::shared_ptr<T> type; };

        template <typename... A>
        typename result<A...>::type operator()(A&&... a) const {
            return std::make_shared<T>(std::forward<A>(a)...);
        }
    };

    template <typename T>
    using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}




namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;


template<typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper>
{


    SystemParser() : SystemParser::base_type(variable_group_)
    {
        namespace phx = boost::phoenix;
        using qi::_1;
        using qi::_val;
        using qi::eps;
        using qi::lit;


        var_counter = 0;

        declarative_symbols.add("variable_group",0);

        variable_group_ = "variable_group" > genericvargp_ > ';';
        genericvargp_ = new_variable_ % ','; //
        new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>() (_1)];
        unencountered_symbol_ = valid_variable_name_ - ( encountered_variables | declarative_symbols );
        valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_") );



//      debug(variable_group_); debug(unencountered_symbol_); debug(new_variable_); debug(genericvargp_);
//      BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
    }


    // rule declarations.  these are member variables for the parser.
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > variable_group_;
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > genericvargp_;
    qi::rule<Iterator, std::shared_ptr<std::string()> >  new_variable_;
    qi::rule<Iterator, std::string()> unencountered_symbol_;
    qi::rule<Iterator, std::string()> valid_variable_name_;


    unsigned var_counter;
    qi::symbols<char,int> encountered_variables;
    qi::symbols<char,int> declarative_symbols;
};

带有驱动程序代码:

int main(int argc, char** argv)
{

    std::vector<std::shared_ptr<std::string> > V;
    std::string str = "variable_group x, y, z; ";


    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();


    SystemParser<std::string::const_iterator> S;


    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);

    if (s)
    {
        std::cout << "Parse succeeded: " << V.size() << " variables\n";
        for (auto& s : V)
            std::cout << " - '" << s << "'\n";
    }
    else
        std::cout << "Parse failed\n";

    if (iter!=end)
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";


    return 0;
}

文本被正确解析,但生成的 vector 长度为​​ 0,而它的长度应为 3。不知何故,std::shared_ptr<string>没有被推到由规则 genericvargp_ 产生的 vector 的背面.

我已经尝试了很多事情,包括从测试解析中读取所有调试信息,以及放置 %=规则定义的标志,应用于具有不分配 _val 的语义操作的规则除非我弄错了。我也玩了一整天 phx::bind手动推到 _val 的背面,却一事无成。我进一步验证了 make_shared_ sehe 在另一个答案中提供的实际上是 std::shared_ptr 的懒惰。

顺便说一句,我也一直在努力获得 unencountered_symbol_ 的结果。添加到 encountered_variables以强制变量名的唯一性...

问题似乎是 new_variable_ 的结果的传播规则到 genericvargp_ 中所需的共享指针 vector 规则。

最佳答案

这个声明

qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_;

与所需类型不匹配:

qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;

遗憾的是,在旧的 SpiritV2 中,这个属性被默默地忽略了,并且没有进行属性传播。这也解释了为什么它没有在编译时出错。

Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#define BOOST_SPIRIT_DEBUG 1

#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>

#include <boost/spirit/include/phoenix_stl.hpp>

#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

// this solution for lazy make shared comes from the SO forum, user sehe.
// https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared
//    post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
    template <typename T> struct make_shared_f {
        template <typename... A> struct result { typedef std::shared_ptr<T> type; };

        template <typename... A> typename result<A...>::type operator()(A &&... a) const {
            return std::make_shared<T>(std::forward<A>(a)...);
        }
    };

    template <typename T> using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}

namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> {

    SystemParser() : SystemParser::base_type(variable_group_) {
        namespace phx = boost::phoenix;
        using qi::_1;
        using qi::_val;
        using qi::eps;
        using qi::lit;

        var_counter = 0;

        declarative_symbols.add("variable_group", 0);

        variable_group_       = "variable_group" > genericvargp_ > ';';
        genericvargp_         = new_variable_ % ',';                                                                                      //
        new_variable_         = unencountered_symbol_ [_val = make_shared_<std::string>()(_1)];
        unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols);
        valid_variable_name_  = +qi::alpha >> *(qi::alnum | qi::char_("[]_"));

        BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
    }

    // rule declarations.  these are member variables for the parser.
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> variable_group_;
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> genericvargp_;
    qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;
    qi::rule<Iterator, std::string()> unencountered_symbol_;
    qi::rule<Iterator, std::string()> valid_variable_name_;

    unsigned var_counter;
    qi::symbols<char, qi::unused_type> encountered_variables;
    qi::symbols<char, qi::unused_type> declarative_symbols;
};

int main()
{
    std::vector<std::shared_ptr<std::string> > V;
    std::string str = "variable_group x, y, z; ";

    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();

    SystemParser<std::string::const_iterator> S;

    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);

    if (s)
    {
        std::cout << "Parse succeeded: " << V.size() << " variables\n";
        for (auto& s : V)
            std::cout << " - '" << *s << "'\n";
    }
    else
        std::cout << "Parse failed\n";

    if (iter!=end)
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}

打印

Parse succeeded: 3 variables
 - 'x'
 - 'y'
 - 'z'

还有很多调试信息

关于c++ - 从灵气中制作共享指针的 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30763212/

相关文章:

c++ - Boost Karma:使用 boost::optional<boost::variant<...>> 编写规则

c++ - boost::spirit::lex 和空格的问题

c++ - strtoul 不是字节序安全的吗?

c++ - 如何从链接器错误转到源代码中的代码行?

c++ - 对 std::lock 的调用是否可以传递已被调用线程锁定的资源?

c++ - 获取实例类成员函数的函数指针?

c++ - shared_ptr 交换线程安全吗?

c++ - boost::dynamic_pointer_cast 在有效转换时返回 null

c++ - 使用 brace-init 初始化对 std::shared_ptr 的引用

c++ - boost 变体 : How to model JSON?