C++ 提升精神模板专业化失败

C++ 提升精神模板专业化失败,c++,boost,boost-spirit,boost-spirit-qi,C++,Boost,Boost Spirit,Boost Spirit Qi,下面是我试图用boost::spirit::qi编写的语法的一个非常简洁的版本。 环境:VS2013、x86、Boost1.64 当包含头文件时,编译器会抱怨行 rBlock = "{" >> +(rInvocation) >> "}"; 日志很长(我只复制了开头和结尾): 多个部分专门化与模板参数列表匹配 … … 请参阅函数模板实例化的参考 '提振::精神::气::规则 &正在编译boost::spirit::qi::rule::operator=>(const Ex

下面是我试图用boost::spirit::qi编写的语法的一个非常简洁的版本。
环境:VS2013、x86、Boost1.64
当包含头文件时,编译器会抱怨行

rBlock = "{" >> +(rInvocation) >> "}";
日志很长(我只复制了开头和结尾):

多个部分专门化与模板参数列表匹配 …

请参阅函数模板实例化的参考 '提振::精神::气::规则 &正在编译boost::spirit::qi::rule::operator=>(const Expr&)

我的错在哪里

头文件:

//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) >> "}";
        }
    };
}
//mygrammar.h
#布拉格语一次
#包括
名称空间myNS
{
typedef std::字符串标识符;
typedef::boost::spirit::qi::rule myIdentifierRule;
typedef::boost::variant表达式;
typedef::boost::spirit::qi::rule myExpressionRule;
结构标识符参数
{
标识符标识符;
表达arg;
};
typedef::boost::variant参数;
typedef::boost::spirit::qi::rule myArgumentRule;
typedef::std::向量参数列表;
typedef::boost::spirit::qi::rule myArgumentListRule;
结构调用
{
标识符;
::boost::可选参数;
};
typedef::boost::spirit::qi::rule myInvocationRule;
typedef::std::向量块;
typedef::boost::spirit::qi::rule myBlockRule;
}
增强融合适应结构(
myNS::IdntifierEqArgument,
(自动,识别)
(自动,arg)
);
增强融合适应结构(
myNS::调用,
(自动,标识符)
(自动,args)
);
名称空间myNS
{
结构myRules
{
桃金娘;
myExpressionRule rExpression;
我的爱是稀有的;
myArgumentListRule rArgumentList;
我的职业;
myBlockRule-rBlock;
myRules()
{
使用名称空间::boost::spirit;
使用名称空间::boost::spirit::qi;
rIdentifier=as_字符串[((qi::alpha |'')>*(qi::alnum |''))];
rExpression=char|int|;
rArgument=(rIdentifier>>“=”>>再加压)|再加压;
rArgumentList=rArgument>>*(“,”>>rArgument);
RINOBIATE=rIdentifier>>“(“>>-rArgumentList>>”);
rBlock=“{”>>+(rinjournal)>>“}”;
}
};
}

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

从概念上讲,这可能是由具有相似/兼容布局的属性类型触发的。在语言理论中,您看到的是C++的命名类型系统与属性传播系统中的结构类型近似之间的不匹配。但足够的理论:)

我不认为
attr\u cast
会在这里拯救你,因为它可能在引擎盖下使用相同的机制和启发式

它引起了我的注意,使
参数列表
可选是。。。不是很有用(因为空列表已经准确地反映了缺少参数)

所以我试着简化规则:

rArgumentList = -(rArgument % ',');
rInvocation   = rIdentifier >> '(' >> rArgumentList >> ')';
声明的属性类型可以是
ArgumentList
,而不是
boost::optional::ArgumentList

事实证明,当传播到
向量时,这会消除歧义,因此。。。你得救了

如果你觉得这是“偶然的”,你应该这样做!如果这不是“偶然”消除了歧义,我会怎么做?我会创建一个语义动作,通过更简单的机制来传播调用。很有可能
fusion::push_-back(\u-val,\u-1)
或类似的方法会奏效

另见

回顾和演示 在这里的清理评论中,我介绍了一些修复/改进以及转储解析的AST的测试运行

  • 将AST与解析器分开(您不希望在AST类型中使用
    qi
    。您特别不希望在通用模板库中使用
    名称空间
    指令)
  • 不要在自适应宏中使用
    auto
    。这不是一个功能。相反,因为表面上可以使用C++11,所以可以使用基于C++11(decltype)的宏

    BOOST_FUSION_ADAPT_STRUCT(myAST::IdntifierEqArgument, ident,arg);
    BOOST_FUSION_ADAPT_STRUCT(myAST::Invocation, identifier,args);
    
  • AST处于领先地位(为了清晰起见,更喜欢c++11):

    我强烈建议使用这些设施

  • 总之,解析器归结为

    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;
        };
    }
    

    我会考虑通过将<代码>标识符QualGuangs<代码>重命名为更具表现力的东西,比如<代码>命名参数。按照前一种约定,您可以将Expression
    命名为AnyLooseCharacterOrIntegralNumber
    。很可能很清楚哪个更好,以及为什么:)
    //#define BOOST_SPIRIT_DEBUG
    BOOST_SPIRIT_DEBUG_NODES((start)(rBlock)(rInvocation)(rIdentifier)(rArgumentList)(rArgument)(rExpression))
    
    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";
    }
    
    //#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: '
    '