C++ 单成员结构的灵气属性传播问题
我对Spirit Qi有一个编译问题,它抱怨value_type不是标识符的成员。出于某种原因,Qi的属性系统将标识符视为容器类型,并尝试枚举其值类型 这是一个与中类似的问题,但是,我认为原因是单成员结构,可能与此相关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,名称) ) 增强融合适应结构( 问题 (
#包括
#包括
#包括
使用名称空间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
这实际上只是推迟了使用融合自适应ifidentifier
的魔法属性转换,从而打破了魔咒:
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;
}