【问题标题】:boost spirit grammar error - "no type named ‘size’ in ‘struct boost::spirit::unused_type’"boost Spirit 语法错误 - “‘struct boost::spirit::unused_type’中没有名为‘size’的类型”
【发布时间】:2013-11-18 11:38:14
【问题描述】:

请帮助我诊断以下错误。我有一个简单的语法:

struct json_start_elem_grammar_object : qi::grammar<StreamIterator,
                                                  void(const CharType*, CharType),
                                                  ascii::space_type>
{
  json_start_elem_grammar_object() : json_start_elem_grammar_object::base_type(start_elem, "start_elem")
  {
    start_elem =  qi::lit('"') > qi::lit(qi::_1) > qi::lit('"') > qi::lit(':') >
                  qi::lit(qi::_2) > -qi::lit('\n');
  }

  qi::rule<StreamIterator, void(const CharType*, CharType), ascii::space_type>  start_elem;
};

创建此语法的实例时出现错误:

/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:220:19:   required from ‘boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>& boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::operator=(const Expr&) [with Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::greater, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::greater, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::greater, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::greater, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::greater, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector1<char> > >, 0l>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::lazy_terminal<boost::spirit::tag::lit, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::detail::function_eval<1>, boost::fusion::vector<boost::phoenix::value<boost::spirit::terminal<boost::spirit::tag::lit> >, boost::spirit::argument<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >, 1> >, 0l>&>, 2l>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector1<char> > >, 0l>&>, 2l>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector1<char> > >, 0l>&>, 2l>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::lazy_terminal<boost::spirit::tag::lit, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::detail::function_eval<1>, boost::fusion::vector<boost::phoenix::value<boost::spirit::terminal<boost::spirit::tag::lit> >, boost::spirit::argument<1>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >, 1> >, 0l>&>, 2l>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::negate, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector1<char> > >, 0l>&>, 1l>&>, 2l>; Iterator = boost::spirit::basic_istream_iterator<char>; T1 = void(const char*, char); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
/home/marcin/workspace/json_archive/basic_json_grammar.hpp:149:18:   required from ‘boost::archive::basic_json_grammar<CharType>::json_start_elem_grammar_object::json_start_elem_grammar_object() [with CharType = char]’
/home/marcin/workspace/json_archive/basic_json_grammar.hpp:194:50:   required from ‘boost::archive::basic_json_grammar<CharType>::basic_json_grammar() [with CharType = char]’
/home/marcin/workspace/json_archive/json_iarchive_impl.ipp:141:85:   required from ‘boost::archive::json_iarchive_impl<Archive>::json_iarchive_impl(std::istream&, unsigned int) [with Archive = boost::archive::naked_json_iarchive; std::istream = std::basic_istream<char>]’
/home/marcin/workspace/json_archive/json_iarchive.hpp:102:68:   required from here
/usr/include/boost/fusion/sequence/intrinsic/size.hpp:33:20: error: no type named ‘size’ in ‘struct boost::spirit::unused_type’
         struct unsegmented_size : Sequence::size {};

在哪里

using CharType = char;
using StreamIterator = spirit::basic_istream_iterator<CharType>;

在处理 boost.serialization 和 boost.spirit 编译错误几天后,我完全脑死了,似乎被困在这个问题上:/

这个语法的用法(略简化)是:

json_start_elem_grammar_object start_elem_parser_object;
using invoker = _details::invoke_grammar<CharType, decltype(start_elem_parser_object(name, preamble))>;

invoker::apply( is,
              start_elem_parser_object(name, preamble),
              "Invalid object element in archive");

在哪里

decltype(is) = IStream& 
decltype(name) = const CharType* 
decltype(preamble) = CharType 


template<typename CharType, typename Expr>
struct invoke_grammar<CharType, Expr> {
 using IStream = std::basic_istream<CharType>;
 using StreamIterator = spirit::basic_istream_iterator<CharType>;

 static void apply(IStream & is, Expr const& grammar, const CharType* errMsg)
 {
   boost::io::ios_flags_saver ifs(is);
   is.unsetf (std::ios::skipws);

   StreamIterator it_end;
   StreamIterator it_beg (is);

   if (!qi::phrase_parse(it_beg, it_end,
                        grammar,
                        ascii::space))
   {
     boost::serialization::throw_exception(
       archive_exception(archive_exception::invalid_signature, errMsg)
     );
   }
 }
};

【问题讨论】:

  • 我们需要用到这个语法。
  • 继承的属性是qi::_r1qi::_r2等(不是_1_2)。另外,请查看qi::symbols&lt;&gt; 以避免在此处使用继承的属性。如果你想编写一个语法 control-freak-style 我认为你最好不用 Spirit 来滚动它。
  • @ForEveR 我已经在问题中添加了使用说明
  • @sehe qi::_rX 和 qi::X 在这种情况下会产生相同的编译错误。在选择占位符时,我咨询了 boost-spirit.com/home/2010/03/03/…,从中我了解到 _1 和 _2 在整个解析器的上下文中是可以的 - 如果我错了,请纠正我。我不想使用符号,因为名称和前导码在运行时很晚才知道,并且更容易将它们作为继承属性传递给解析器。谢谢
  • @Marcin 占位符是“好的”,但它们的含义不同(如果你仔细想想,这实际上很有意义)

标签: c++ boost boost-spirit-qi


【解决方案1】:

就像我评论的那样,您需要使用 qi::_r1qi::_r2inherited attributes 的占位符[1]

对于其余部分,我可以假设(因为您的代码不完整,并且由于非标准方法对我来说有点不清楚):

  • 您可能希望 ascii::blank_type 作为船长,否则 lit('\n') 将永远不会匹配(除非与 no_skip[]lexeme[] 匹配)。
  • 您必须小心使用实际的CharType const* 调用解析器,而不是CharType const (&amp;)[]。如果您使用例如调用它,则会发生后者parser("name", 'a')。相反,无论是

    • 引入一个临时变量
    • 演员表
    • 隐式衰减使用例如+"name"

我做了一个例子,它成功了,看看它Live on Coliru

完整代码:

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>

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

template <typename StreamIterator, typename CharType=char>
struct json_start_elem_grammar_object : qi::grammar<StreamIterator,
    void(const CharType*, CharType),
    ascii::blank_type>
{
    json_start_elem_grammar_object() : json_start_elem_grammar_object::base_type(start_elem, "start_elem")
    {
        using namespace qi;
        _r1_type _name;     // prefer descriptive names
        _r2_type _preamble;

        start_elem = 
            '"' > lit(_name) > '"' > 
            ':' > lit(_preamble) > 
            -lit('\n')
            ;
    }

    qi::rule<StreamIterator, void(const CharType*, CharType), ascii::blank_type>  start_elem;
};

bool doParse(const std::string& input)
{
    typedef std::string::const_iterator It;
    auto f(begin(input)), l(end(input));

    json_start_elem_grammar_object<It> p;

    try
    {
        bool ok = qi::phrase_parse(f, l, p(+"lol", 'q'), ascii::blank);
        if (ok)   
        {
            std::cout << "parse success\n";
        }
        else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

        if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
        return ok;
    } catch(const qi::expectation_failure<It>& e)
    {
        std::string frag(e.first, e.last);
        std::cerr << e.what() << "'" << frag << "'\n";
    }

    return false;
}

int main()
{
    bool ok = doParse("\"lol\" : q\n");
    return ok? 0 : 255;
}

[1]另见

【讨论】:

  • 非常感谢您的帮助。我遇到的具体错误是 boost bug svn.boost.org/trac/boost/ticket/8774 的结果。放置“BOOST_RESULT_OF_USE_TR1”定义修复了编译错误。我接受了你的回答,因为你指出了我犯的一些其他错误。很抱歉让你“预言”了答案。由于存在的交互数量,我无法(在合理的时间内)产生 100% 准确的 SSCCE。我使用 boost.spirit 为 boost.serialization 框架添加了一些功能。很难找到最小的例子。
  • 我感觉BOOST_RESULT_OF_USE_DECLTYPE 可能会自动为最近的编译器定义,但是PhoenixV2 不能使用它(?)。与其“回到过去”(使用 TR1 结果协议),不如考虑与时俱进(如我的示例所示)并改为定义BOOST_SPIRIT_USE_PHOENIX_V3。我高度怀疑这也会起作用。
  • 哦,还有:你得到的具体错误是不是因为那个错误:这是因为使用_1而不是_r1(见coliru.stacked-crooked.com/a/854d1f1cca5b92c4 )
  • 是的,我的代码中有不止一个错误。我可能把一个错误误认为另一个错误。再次感谢。正如你猜到的,我使用的是 Spirit V2——这个版本是我正在开发的产品的要求。干杯!
  • 请仔细阅读。 BOOST_SPIRIT_USE_PHOENIX_V3 很像 Spirit V2。事实上,以我的经验,SpiritV2 中的 PhoenixV2 支持更像是一个遗留问题(PhoenixV3 中已经修复了许多错误,我从未见过由于使用 PhoenixV3 而导致 Spirit 出现任何问题)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
相关资源
最近更新 更多