Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 单成员结构的灵气属性传播问题_C++_Boost Spirit_Boost Spirit Qi_Boost Fusion - Fatal编程技术网

C++ 单成员结构的灵气属性传播问题

C++ 单成员结构的灵气属性传播问题,c++,boost-spirit,boost-spirit-qi,boost-fusion,C++,Boost Spirit,Boost Spirit Qi,Boost Fusion,我对Spirit Qi有一个编译问题,它抱怨value_type不是标识符的成员。出于某种原因,Qi的属性系统将标识符视为容器类型,并尝试枚举其值类型 这是一个与中类似的问题,但是,我认为原因是单成员结构,可能与此相关 #包括 #包括 #包括 使用名称空间boost::spirit::qi; 结构标识符 { std::wstring名称; }; 结构问题 { 标识符1; 标识符2; 标识符3; }; 增强融合适应结构( 标识符, (标准::wstring,名称) ) 增强融合适应结构( 问题 (

我对Spirit Qi有一个编译问题,它抱怨value_type不是标识符的成员。出于某种原因,Qi的属性系统将标识符视为容器类型,并尝试枚举其值类型

这是一个与中类似的问题,但是,我认为原因是单成员结构,可能与此相关

#包括
#包括
#包括
使用名称空间boost::spirit::qi;
结构标识符
{
std::wstring名称;
};
结构问题
{
标识符1;
标识符2;
标识符3;
};
增强融合适应结构(
标识符,
(标准::wstring,名称)
)
增强融合适应结构(
问题
(标识符,_1)
(标识符,_2)
(标识符,_3)
)
int main(int argc,char*argv[])
{
规则gr|U identifier=eps>>原始[lexeme[(alpha |'')>*(alnum |'')];
//好的,编译
/*规则gr\u问题=gr\u标识符
>>gr_标识符
>> '('
>>gr_标识符
>>   ')';*/
//失败
规则gr\u问题=gr\u标识符
>>gr_标识符
>> '('
>gr_标识符
>   ')';
std::wstring输入=L“foo-goo(hoo)”;
/*bool dummy=短语解析(
input.begin(),input.end(),
gr_问题,
空间)*/
返回退出成功;
}
有趣的是,只有在使用期望解析器时才会发生这种情况(请参见示例中的定义2)。定义1仅使用序列解析器,正确编译(和执行)

有人知道解决这个问题的正确方法吗


还请查看

这是一个相当臭名昭著的边缘案例。问题是,单元素融合序列的特殊情况处理在精神上打破了一些抽象

通常的解决方法是调整暴露的属性端,使其不那么琐碎:

rule<It, single_member_struct()> r = eps >> XXX; 
// the `eps` is there to break the spell
这实际上只是推迟了使用融合自适应if
identifier
的魔法属性转换,从而打破了魔咒:

rule<It, problem(), qi::space_type> gr_problem = 
       gr_identifier
    >> gr_identifier
    >> ('(' > gr_identifier > ')')
    ;
现在:

rule<It, identifier()> gr_identifier = 
    (alpha | '_') >> *(alnum | '_') >> attr(42);   // that's hacky
请注意,为了允许属性传播,现在需要提供合适的转换构造函数。此外,Spirit中公开的属性需要默认构造函数

现在,

规则gr\u标识符=
as_string[(alpha |'')>*(alnum |'')]//清洁工但没有融合
工作。如果您不需要将该类型的融合用于其他目的,这可能会更直观

注意:这个变体在编译时可能是最有效的

总结 我认为对于您的代码,有两个完全可行的变通方法(#1和#3),还有一个不太理想(带有虚拟字段的),但我将其包括在文档中

完整代码 供日后参考

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

namespace qi = boost::spirit::qi;

//////////////////////////////////////////
// Select workaround to demonstrate
#define KEEP_STRING_WORKAROUND
// #define DUMMY_WORKAROUND™
// #define NO_ADAPT_WORKAROUND
//////////////////////////////////////////

#if defined(KEEP_STRING_WORKAROUND)
    struct identifier
    {
        std::string    name;
    };

    BOOST_FUSION_ADAPT_STRUCT(
        identifier,
        (std::string,    name)
    )
#elif defined(DUMMY_WORKAROUND)
    struct identifier
    {
        std::string    name;
        qi::unused_type dummy;
    };

    BOOST_FUSION_ADAPT_STRUCT(
        identifier,
        (std::string,    name)
        (qi::unused_type, dummy)
    )
#elif defined(NO_ADAPT_WORKAROUND)
    struct identifier
    {
        std::string name;

        identifier() = default;

        explicit identifier(std::string name) 
            : name(std::move(name))
        {}
    };
#endif

struct problem
{
    identifier _1;
    identifier _2;
    identifier _3;
};

BOOST_FUSION_ADAPT_STRUCT(
    problem,
    (identifier, _1)
    (identifier, _2)
    (identifier, _3)
)

//////////////////////////////////////////
// For BOOST_SPIRIT_DEBUG only:
static inline std::ostream& operator<<(std::ostream& os, identifier const& id) {
    return os << id.name;
}
//////////////////////////////////////////

int main()
{
    using namespace qi;
    typedef std::string::const_iterator It;
#if defined(KEEP_STRING_WORKAROUND)
    rule<It, std::string()> gr_identifier = 
        (alpha | '_') >> *(alnum | '_');
#elif defined(DUMMY_WORKAROUND)
    rule<It, identifier()> gr_identifier = 
        (alpha | '_') >> *(alnum | '_') >> attr(42);   // that's hacky
#elif defined(NO_ADAPT_WORKAROUND)
    rule<It, identifier()> gr_identifier = 
        as_string [ (alpha | '_') >> *(alnum | '_') ]; // cleaner... but no fusion
#endif

    rule<It, problem(), qi::space_type> gr_problem = 
           gr_identifier
        >> gr_identifier
        >> ('(' > gr_identifier > ')')
        ;

    std::string input = "foo goo(hoo)";

    BOOST_SPIRIT_DEBUG_NODES((gr_problem)(gr_identifier));

    It f(begin(input)), l(end(input));
    bool dummy = phrase_parse(f, l, gr_problem, qi::space);

    return dummy? 0 : 255;
}
#定义BOOST\u SPIRIT\u DEBUG
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
//////////////////////////////////////////
//选择要演示的解决方案
#定义KEEP_STRING_解决方法
//#定义虚拟#u解决方法™
//#定义无需调整的解决方案
//////////////////////////////////////////
#如果已定义(保留字符串\u解决方法)
结构标识符
{
std::字符串名;
};
增强融合适应结构(
标识符,
(std::字符串,名称)
)
#已定义elif(虚拟_解决方案)
结构标识符
{
std::字符串名;
qi::未使用的_型假人;
};
增强融合适应结构(
标识符,
(std::字符串,名称)
(qi::未使用的_类型,虚拟)
)
#已定义elif(无调整解决方案)
结构标识符
{
std::字符串名;
标识符()=默认值;
显式标识符(std::字符串名称)
:名称(标准::移动(名称))
{}
};
#恩迪夫
结构问题
{
标识符1;
标识符2;
标识符3;
};
增强融合适应结构(
问题
(标识符,_1)
(标识符,_2)
(标识符,_3)
)
//////////////////////////////////////////
//仅适用于BOOST_SPIRIT_调试:
静态内联std::ostream&operator>*(alnum |'"'>>attr(42);//那太令人讨厌了
#已定义elif(无调整解决方案)
规则gr_标识符=
as_string[(alpha |'')>*(alnum |'')]//清洁工但没有融合
#恩迪夫
规则gr_问题=
gr_标识符
>>gr_标识符
>>(“(“>gr_标识符>”)”
;
std::string input=“foo-goo(hoo)”;
BOOST_SPIRIT_DEBUG_节点((gr_问题)(gr_标识符));
它是f(开始(输入)),l(结束(输入));
bool dummy=短语解析(f,l,gr_问题,qi::space);
返回假人?0 : 255;
}

[1] 相信我,即使在插入
qi::unused_type
“fake”属性和/或使用
attr_cast
或助手规则强制子表达式的类型时,我也尝试过


[2] 出于演示的目的,我使用了
std::string
,因为我相信它与BOOST\u SPIRIT\u DEBUG更好地结合在一起

,但是如何处理单字段类,哪个字段是容器?说
struct-rvalue\u-list:taged{std::dequervalues\u}。我是否可以声明和定义c-tor,比如
模板rvalue_list::rvalue_list(Iterator const_first,Iterator const_last):rvalues_(_first,_last){;}
?@Dukales no?您将使构造函数接受公开的属性。无论如何,这里有一种直接的方法:-另一种方法是使用定制的
traits
来分配给您的单字段类,即t
struct identifier
{
    std::string    name;
    qi::unused_type dummy;
};

BOOST_FUSION_ADAPT_STRUCT(
    identifier,
    (std::string,    name)
    (qi::unused_type, dummy)
)
rule<It, identifier()> gr_identifier = 
    (alpha | '_') >> *(alnum | '_') >> attr(42);   // that's hacky
struct identifier
{
    std::string name;

    identifier() = default;

    explicit identifier(std::string name) 
        : name(std::move(name))
    {}
};
rule<It, identifier()> gr_identifier = 
    as_string [ (alpha | '_') >> *(alnum | '_') ]; // cleaner... but no fusion
#define BOOST_SPIRIT_DEBUG
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace qi = boost::spirit::qi;

//////////////////////////////////////////
// Select workaround to demonstrate
#define KEEP_STRING_WORKAROUND
// #define DUMMY_WORKAROUND™
// #define NO_ADAPT_WORKAROUND
//////////////////////////////////////////

#if defined(KEEP_STRING_WORKAROUND)
    struct identifier
    {
        std::string    name;
    };

    BOOST_FUSION_ADAPT_STRUCT(
        identifier,
        (std::string,    name)
    )
#elif defined(DUMMY_WORKAROUND)
    struct identifier
    {
        std::string    name;
        qi::unused_type dummy;
    };

    BOOST_FUSION_ADAPT_STRUCT(
        identifier,
        (std::string,    name)
        (qi::unused_type, dummy)
    )
#elif defined(NO_ADAPT_WORKAROUND)
    struct identifier
    {
        std::string name;

        identifier() = default;

        explicit identifier(std::string name) 
            : name(std::move(name))
        {}
    };
#endif

struct problem
{
    identifier _1;
    identifier _2;
    identifier _3;
};

BOOST_FUSION_ADAPT_STRUCT(
    problem,
    (identifier, _1)
    (identifier, _2)
    (identifier, _3)
)

//////////////////////////////////////////
// For BOOST_SPIRIT_DEBUG only:
static inline std::ostream& operator<<(std::ostream& os, identifier const& id) {
    return os << id.name;
}
//////////////////////////////////////////

int main()
{
    using namespace qi;
    typedef std::string::const_iterator It;
#if defined(KEEP_STRING_WORKAROUND)
    rule<It, std::string()> gr_identifier = 
        (alpha | '_') >> *(alnum | '_');
#elif defined(DUMMY_WORKAROUND)
    rule<It, identifier()> gr_identifier = 
        (alpha | '_') >> *(alnum | '_') >> attr(42);   // that's hacky
#elif defined(NO_ADAPT_WORKAROUND)
    rule<It, identifier()> gr_identifier = 
        as_string [ (alpha | '_') >> *(alnum | '_') ]; // cleaner... but no fusion
#endif

    rule<It, problem(), qi::space_type> gr_problem = 
           gr_identifier
        >> gr_identifier
        >> ('(' > gr_identifier > ')')
        ;

    std::string input = "foo goo(hoo)";

    BOOST_SPIRIT_DEBUG_NODES((gr_problem)(gr_identifier));

    It f(begin(input)), l(end(input));
    bool dummy = phrase_parse(f, l, gr_problem, qi::space);

    return dummy? 0 : 255;
}