【问题标题】:boost::spirit parsing into struct with std::arrayboost::spirit 用 std::array 解析成结构
【发布时间】:2015-12-23 11:54:48
【问题描述】:

我正在使用 boost::spirit 将文本解析为包含固定大小数组的结构。在遵循

中的示例时

qi/boost_array.cpp

并尝试使用它来解析包含 std::array(或 boost::array)的结构,我认识到由于 BOOST_FUSION_ADAPT_STRUCT 的工作原理,我必须放置帮助器 result_of::adapt_array::type 在结构中也是如此。

我认为应该可以使用 BOOST_FUSION_ADAPT_ADT 创建一个包装器,但是仅仅为了摆脱结构中的小适配器开销似乎有点过头了。由于我没有太多实例,从记忆的角度来看,我可以忍受它,但它也会引入一些噪音。

我还认为可以创建一个从数组类型派生的适配器,而不是封装它以隐藏一些噪音,但它会迫使我改变所有现有的结构,并且它会将解析器开销泄漏到外部不是一个好的解决方案。

是否有一些明显的问题我正在接近错误,或者确实存在新的帮助器,它们在后台路由开销以便可以将它们封装在解析器中?

我知道 Using std::array as Attribute for boost::spirit::x3.

Live Example

这是我当前的代码:

#include <string>
#include <array>
#include <boost/spirit/include/qi.hpp>

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

// ...code from http://www.boost.org/doc/libs/1_60_0/libs/spirit/example/qi/boost_array.cpp here

typedef result_of::adapt_array<std::array<double, 6> >::type AdaptedArrayType;

struct StructWithArray
{
    StructWithArray()
        : adaptedAry_(ary_)
    {}

    double dummy_; // see https://stackoverflow.com/questions/19823413/spirit-qi-attribute-propagation-issue-with-single-member-struct
    std::array<double, 6> ary_;
    AdaptedArrayType adaptedAry_;
};

BOOST_FUSION_ADAPT_STRUCT(
    StructWithArray
    ,
    (double, dummy_)
    (AdaptedArrayType, adaptedAry_)
    )

template <typename Iterator, typename Skipper>
struct StructWithArrayParser
    : qi::grammar<Iterator, StructWithArray(), Skipper>
{
    StructWithArrayParser() : StructWithArrayParser::base_type(start)
    {
        using qi::double_;

        arrayLine %= double_ > double_ > double_ > double_ > double_ > double_;
        start %= double_ > arrayLine;
    }

    qi::rule<Iterator, AdaptedArrayType(), Skipper> arrayLine;
    qi::rule<Iterator, StructWithArray(), Skipper> start;
};

int main() {
    std::string arrayStr = "0 1 2 3 4 5 6";
    std::string::const_iterator it = arrayStr.begin();
    std::string::const_iterator endIt = arrayStr.end();
    StructWithArrayParser<std::string::const_iterator, ascii::space_type> grammar;
    StructWithArray structWithArray;
    bool ret = phrase_parse(it, endIt, grammar, ascii::space, structWithArray);
    return 0;
}

【问题讨论】:

    标签: c++ c++11 boost-spirit-qi boost-fusion stdarray


    【解决方案1】:

    你要去的地方 :) 你似乎很快就用 Spirit 达到了曲速。

    已编辑仔细阅读问题后,我注意到您要求的方式更短、干扰更少。

    我不知道修复它的非侵入式方法,但如果您专门针对它使用 is_container,则可以使用 boost::array

    这很不打扰,但仍然会改变你的类型。

    Live On Coliru

    #include <boost/fusion/include/tuple.hpp>
    #include <boost/fusion/adapted/boost_array.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <string>
    
    namespace boost { namespace spirit { namespace traits {
        template <typename T, size_t N>
            struct is_container<boost::array<T, N>, void> : mpl::false_ { };
    } } }
    
    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    
    struct StructWithArray
    {
        double dummy_; // see http://stackoverflow.com/questions/19823413/spirit-qi-attribute-propagation-issue-with-single-member-struct
        boost::array<double, 6> ary_;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(StructWithArray, dummy_, ary_)
    
    template <typename Iterator, typename Skipper>
    struct StructWithArrayParser
        : qi::grammar<Iterator, StructWithArray(), Skipper>
    {
        StructWithArrayParser() : StructWithArrayParser::base_type(start)
        {
            using qi::double_;
    
            arrayLine = double_ > double_ > double_ > double_ > double_ > double_;
            start     = double_ > arrayLine;
        }
    
      private:
        qi::rule<Iterator, boost::array<double, 6>(), Skipper> arrayLine;
        qi::rule<Iterator, StructWithArray(), Skipper> start;
    };
    
    int main() {
        std::string arrayStr = "0 1 2 3 4 5 6";
        using It = std::string::const_iterator;
        It it = arrayStr.begin(), endIt = arrayStr.end();
        StructWithArrayParser<It, ascii::space_type> grammar;
    
        StructWithArray structWithArray;
        bool ret = phrase_parse(it, endIt, grammar, ascii::space, structWithArray);
        std::cout << std::boolalpha << ret << "\n";
    
        for (double v : structWithArray.ary_)
            std::cout << v << " ";
    }
    

    打印:

    true
    1 2 3 4 5 6 
    

    【讨论】:

    • 在使用 boost 1.58,59,60 测试了{g++,clang++} -std={c++03,c++11,c++14} 的所有排列后,我发现问题被误读了。马上看
    • 用我可以(轻松)实现的最佳解决方法更新了答案。在我看来,您可能会解决这个问题以模仿 std::array 相同的内容,但它不是现成的
    • 绝妙的解决方法:) 正是我所希望的。我现在可以愉快地使用 boost::array,但如果我有时间让它与 std::array 一起使用,我会进行编辑。您的解决方案将我指向 BOOST_PP_VARIADICS 也很棒;这样更容易。
    • 聪明,稍加改动它也适用于 Spirit X3。 Spirit 应该更清楚,array 不是容器。遗憾的是,这种解决方法不适用于std::array(因为 Spirit 尝试移动阵列)。 /usr/include/boost/spirit/home/x3/support/traits/move_to.hpp:54:18: fatal error: no viable overloaded '='
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多