gpt4 book ai didi

c++ - Boost Spirit模板特化失败

转载 作者:行者123 更新时间:2023-11-30 05:11:12 25 4
gpt4 key购买 nike

下面是我尝试使用 boost::spirit::qi 编写的语法的一个非常紧凑的版本。
环境:VS2013、x86、Boost1.64
当#include 头文件时,编译器会提示该行

rBlock = "{" >> +(rInvocation) >> "}";

日志很长(我只复制了开头和结尾):

more than one partial specialization matches the template argument list ...
...
see reference to function template instantiation 'boost::spirit::qi::rule &boost::spirit::qi::rule::operator =>(const Expr &)' being compiled

我的错误在哪里?

头文件:

//mygrammar.h
#pragma once
#include <boost/spirit/include/qi.hpp>

namespace myNS
{

typedef std::string Identifier;
typedef ::boost::spirit::qi::rule <const char*, Identifier()> myIdentifierRule;

typedef ::boost::variant<char, int> Expression;
typedef ::boost::spirit::qi::rule <const char*, Expression()> myExpressionRule;

struct IdntifierEqArgument
{
Identifier ident;
Expression arg;
};

typedef ::boost::variant < IdntifierEqArgument, Expression > Argument;
typedef ::boost::spirit::qi::rule <const char*, Argument()> myArgumentRule;

typedef ::std::vector<Argument> ArgumentList;
typedef ::boost::spirit::qi::rule <const char*, myNS::ArgumentList()> myArgumentListRule;


struct Invocation
{
Identifier identifier;
::boost::optional<ArgumentList> args;
};
typedef ::boost::spirit::qi::rule <const char*, Invocation()> myInvocationRule;


typedef ::std::vector<Invocation> Block;
typedef ::boost::spirit::qi::rule <const char*, myNS::Block()> myBlockRule;

}
BOOST_FUSION_ADAPT_STRUCT(
myNS::IdntifierEqArgument,
(auto, ident)
(auto, arg)
);
BOOST_FUSION_ADAPT_STRUCT(
myNS::Invocation,
(auto, identifier)
(auto, args)
);

namespace myNS
{
struct myRules
{
myIdentifierRule rIdentifier;
myExpressionRule rExpression;
myArgumentRule rArgument;
myArgumentListRule rArgumentList;
myInvocationRule rInvocation;
myBlockRule rBlock;

myRules()
{
using namespace ::boost::spirit;
using namespace ::boost::spirit::qi;

rIdentifier = as_string[((qi::alpha | '_') >> *(qi::alnum | '_'))];
rExpression = char_ | int_;
rArgument = (rIdentifier >> "=" >> rExpression) | rExpression;
rArgumentList = rArgument >> *("," >> rArgument);
rInvocation = rIdentifier >> "(" >> -rArgumentList >> ")";
rBlock = "{" >> +(rInvocation) >> "}";
}
};
}

最佳答案

我不太确定问题是在哪里触发的,但这显然是属性转发规则中太多歧义的症状。

Conceptually this could be triggered by your attribute types having similar/compatible layouts. In language theory, you're looking at a mismatch between C++'s nominative type system versus the approximation of structural typing in the attribute propagation system. But enough theorism :)

我不认为attr_cast<>将在这里保存您,因为它可能在引擎盖下使用相同的机制和启发式方法。

引起我注意的是制作 ArgumentList可选的是......不是很有用(因为空列表已经准确地反射(reflect)了参数的缺失)。

所以我尝试简化规则:

rArgumentList = -(rArgument % ',');
rInvocation = rIdentifier >> '(' >> rArgumentList >> ')';

并且声明的属性类型可以是简单的ArgumentList而不是 boost::optional::ArgumentList .

事实证明,这消除了传播到 vector<Invocation> 时的歧义。 ,所以……你得救了。

If this feels "accidental" to you, you should! What would I do if this hadn't removed the ambiguity "by chance"? I'd have created a semantic action to propagate the Invocation by simpler mechanics. There's a good chance that fusion::push_back(_val, _1) or similar would have worked.

See also Boost Spirit: "Semantic actions are evil"?

审查和演示

在这里的清理审查中,我提出了一些修复/改进和转储已解析 AST 的测试运行。

  1. 将 AST 与解析器分开(您不希望在 AST 类型中使用 qi。您特别不希望在通用模板库中使用 using namespace 指令)
  2. 不要使用 auto在自适应宏中。那不是一个功能。相反,由于您表面上可以使用 C++11,因此请使用基于 C++11 (decltype) 的宏

    BOOST_FUSION_ADAPT_STRUCT(myAST::IdntifierEqArgument, ident,arg);
    BOOST_FUSION_ADAPT_STRUCT(myAST::Invocation, identifier,args);
  3. AST 领先(另外,为了清晰起见,更喜欢 c++11):

    namespace myAST {
    using Identifier = std::string;
    using Expression = boost::variant<char, int>;

    struct IdntifierEqArgument {
    Identifier ident;
    Expression arg;
    };

    using Argument = boost::variant<IdntifierEqArgument, Expression>;

    using ArgumentList = std::vector<Argument>;

    struct Invocation {
    Identifier identifier;
    ArgumentList args;
    };

    using Block = std::vector<Invocation>;
    }

    把定义分开真好

  4. 关于解析器,

    • 我更喜欢 qi::grammar习俗。还有,
    • 你没有向 skipper 宣布任何规则。我从上下文中“猜到”空格在 Expression 的规则之外是微不足道的 |和 Identifier .
    • 表情每吃一次char_ ,所以也会吃')'甚至 '3' .我仅在测试时和调试后才注意到这一点:

      //#define BOOST_SPIRIT_DEBUG
      BOOST_SPIRIT_DEBUG_NODES((start)(rBlock)(rInvocation)(rIdentifier)(rArgumentList)(rArgument)(rExpression))

      我强烈推荐使用这些设施

  5. 总而言之,解析器归结为

    namespace myNS {
    namespace qi = boost::spirit::qi;

    template <typename Iterator = char const*>
    struct myRules : qi::grammar<Iterator, myAST::Block()> {

    myRules() : myRules::base_type(start) {
    rIdentifier = qi::raw [(qi::alpha | '_') >> *(qi::alnum | '_')];
    rExpression = qi::alpha | qi::int_;
    rArgument = (rIdentifier >> '=' >> rExpression) | rExpression;
    rArgumentList = -(rArgument % ',');
    rInvocation = rIdentifier >> '(' >> rArgumentList >> ')';
    rBlock = '{' >> +rInvocation >> '}';
    start = qi::skip(qi::space) [ rBlock ];

    BOOST_SPIRIT_DEBUG_NODES((start)(rBlock)(rInvocation)(rIdentifier)(rArgumentList)(rArgument)(rExpression))
    }

    private:
    qi::rule<Iterator, myAST::Block()> start;
    using Skipper = qi::space_type;

    qi::rule<Iterator, myAST::Argument(), Skipper> rArgument;
    qi::rule<Iterator, myAST::ArgumentList(), Skipper> rArgumentList;
    qi::rule<Iterator, myAST::Invocation(), Skipper> rInvocation;
    qi::rule<Iterator, myAST::Block(), Skipper> rBlock;
    // implicit lexemes
    qi::rule<Iterator, myAST::Identifier()> rIdentifier;
    qi::rule<Iterator, myAST::Expression()> rExpression;
    };
    }
  6. 添加测试驱动程序

    int main() {
    std::string const input = R"(
    {
    foo()
    bar(a, b, 42)
    qux(someThing_awful01 = 9)
    }
    )";
    auto f = input.data(), l = f + input.size();

    myAST::Block block;
    bool ok = parse(f, l, myNS::myRules<>{}, block);

    if (ok) {
    std::cout << "Parse success\n";

    for (auto& invocation : block) {
    std::cout << invocation.identifier << "(";
    for (auto& arg : invocation.args) std::cout << arg << ",";
    std::cout << ")\n";
    }
    }
    else
    std::cout << "Parse failed\n";

    if (f!=l)
    std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
    }

完成演示

查看 Live On Coliru

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>

namespace myAST {
using Identifier = std::string;
using Expression = boost::variant<char, int>;

struct IdntifierEqArgument {
Identifier ident;
Expression arg;
};

using Argument = boost::variant<IdntifierEqArgument, Expression>;

using ArgumentList = std::vector<Argument>;

struct Invocation {
Identifier identifier;
ArgumentList args;
};

using Block = std::vector<Invocation>;

// for debug printing
static inline std::ostream& operator<<(std::ostream& os, myAST::IdntifierEqArgument const& named) {
return os << named.ident << "=" << named.arg;
}
}

BOOST_FUSION_ADAPT_STRUCT(myAST::IdntifierEqArgument, ident,arg);
BOOST_FUSION_ADAPT_STRUCT(myAST::Invocation, identifier,args);

namespace myNS {
namespace qi = boost::spirit::qi;

template <typename Iterator = char const*>
struct myRules : qi::grammar<Iterator, myAST::Block()> {

myRules() : myRules::base_type(start) {
rIdentifier = qi::raw [(qi::alpha | '_') >> *(qi::alnum | '_')];
rExpression = qi::alpha | qi::int_;
rArgument = (rIdentifier >> '=' >> rExpression) | rExpression;
rArgumentList = -(rArgument % ',');
rInvocation = rIdentifier >> '(' >> rArgumentList >> ')';
rBlock = '{' >> +rInvocation >> '}';
start = qi::skip(qi::space) [ rBlock ];

BOOST_SPIRIT_DEBUG_NODES((start)(rBlock)(rInvocation)(rIdentifier)(rArgumentList)(rArgument)(rExpression))
}

private:
qi::rule<Iterator, myAST::Block()> start;
using Skipper = qi::space_type;

qi::rule<Iterator, myAST::Argument(), Skipper> rArgument;
qi::rule<Iterator, myAST::ArgumentList(), Skipper> rArgumentList;
qi::rule<Iterator, myAST::Invocation(), Skipper> rInvocation;
qi::rule<Iterator, myAST::Block(), Skipper> rBlock;
// implicit lexemes
qi::rule<Iterator, myAST::Identifier()> rIdentifier;
qi::rule<Iterator, myAST::Expression()> rExpression;
};
}

int main() {
std::string const input = R"(
{
foo()
bar(a, b, 42)
qux(someThing_awful01 = 9)
}
)";
auto f = input.data(), l = f + input.size();

myAST::Block block;
bool ok = parse(f, l, myNS::myRules<>{}, block);

if (ok) {
std::cout << "Parse success\n";

for (auto& invocation : block) {
std::cout << invocation.identifier << "(";
for (auto& arg : invocation.args) std::cout << arg << ",";
std::cout << ")\n";
}
}
else
std::cout << "Parse failed\n";

if (f!=l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}

打印输出

Parse success
foo()
bar(a,b,42,)
qux(someThing_awful01=9,)
Remaining unparsed input: '
'

关于c++ - Boost Spirit模板特化失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45190581/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com