C++ 使用boost::spirit::karma生成时如何避免boost::phoenix
我是错误“LNK1179:无效或损坏的文件:重复COMDAT”的受害者 并让我相信,通过不使用phoenix,我可以避免这个错误 (这是一项后续行动。) 我想用其他东西来取代C++ 使用boost::spirit::karma生成时如何避免boost::phoenix,c++,boost,boost-spirit,boost-bind,boost-phoenix,C++,Boost,Boost Spirit,Boost Bind,Boost Phoenix,我是错误“LNK1179:无效或损坏的文件:重复COMDAT”的受害者 并让我相信,通过不使用phoenix,我可以避免这个错误 (这是一项后续行动。) 我想用其他东西来取代boost::phoenix。可能是boost::bind,但我不知道如何让它访问karma::\u val 以下代码在VC9上编译失败 错误C2825:“F”:后跟“:”时必须是类或命名空间 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 名称空间业力=提升::精神::业力;
boost::phoenix
。可能是boost::bind
,但我不知道如何让它访问karma::\u val
以下代码在VC9上编译失败
错误C2825:“F”:后跟“:”时必须是类或命名空间
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间业力=提升::精神::业力;
名称空间spirit=boost::spirit;
名称空间ascii=boost::spirit::ascii;
名称空间phoenix=boost::phoenix;
类项目
{
公众:
typedef std::向量值;
项(const std::string&i,const Values&v):m_id(i),m_Values(v){}
std::string getId()常量{return m_id;}
const Values&getValues()const{return m_Values;}
私人:
std::字符串m_id;
m_值;
};
类项目列表
{
公众:
typedef std::映射项;
ItemList(){}
ItemList(constitems&s,constitems&o):m_-some(s),m_-other(o){}
const Items getSome()const{return m_some;}
const Items getOther()const{return m_other;}
私人:
项目m_some;;
其他项目;
};
模板
结构列表生成器:karma::grammar
{
列表生成器(const ItemList&i)
:列表\u生成器::基本\u类型(开始)
{
使用因果报应::int;
使用业力::_1;
使用业力:点燃;
使用业力::\u val;
//使用phoenix的原因:致命错误LNK1179:无效或损坏的文件:重复COMDAT“?值@?$result\@U?$member\\变量@$$A6E?AV?$basic_string@DU?$char_traits@D@性病病毒$allocator@D@2@@std@@XZP8Item@@AE?AV12@XZ@detail@phoenix@boost@@@a$is\u mem\u fun\u pointer\u select@$0A@@detail@boost@@2_NB'
//这可能是因为符号名称太长。
//将贴图转换为仅包含值的列表
const Items some=boost::copy_range(i.getSome()| boost::adapters::map_值);
const Items other=boost::copy_range(i.getOther()| boost::adapters::map_值);
身份证=
亮(“”)
具有
1> [
1> R=增压::bi::未指定,
1> F=std::string(uu thiscall Item::*)(void)const,
1> L=boost::_bi::列表2
1> ]
1> .cpp(57):编译类模板成员函数“list\u generator::list\u generator(const ItemList&)”时
1> 与
1> [
1> 迭代器=Iter
1> ]
1> .cpp(116):请参阅对正在编译的类模板实例化“列表生成器”的引用
1> 与
1> [
1> 迭代器=Iter
1> ]
您不能将boost::bind
表达式用作phoenix actor
关于长时间损坏的名称,如果使用其他TMP繁重的库(例如Boost Range,它有自己的模板实例化森林,从适配器返回视图等),我不会感到惊讶
你可以试试
项
结构适应融合序列:(带或不带属性转换
)
- 同样,您可以让
规则本身直接使用一个融合序列项
- 使用多态函数对象(也称为延迟可调用对象)
- 或者使用自由函数
getId()
和getValues()
烘焙自定义phoenix::function
actors(完整性)1.使
项
结构适应融合序列:
- 同样,您可以让
规则本身直接使用一个融合序列,而不是项
实例。这肯定会从解析器表达式中删除所有绑定/代理复杂性,但是需要更多的工作才能让其余生成器连接起来项
- 使用多态函数对象(也称为延迟可调用对象):
这样,您就可以像这样简单地使用:
item = lit("<item>") << id[_1 = phx_getId(_val)] << values[_1 = phx_getValues(_val)] << lit("</item>");
项目= 亮(“”)
不能将
表达式用作phoenix actor 关于长时间损坏的名称,如果使用其他TMP繁重的库(例如Boost Range,它有自己的模板实例化森林,从适配器返回视图等),我不会感到惊讶 你可以试试boost::bind
- 使
结构适应融合序列:(带或不带项
)属性转换
- 同样,您可以让
规则本身直接使用一个融合序列项
- 要“预编译”角色以用于语义操作,请执行以下操作:
- 使用多态函数对象(也称为延迟可调用对象)
- 或者使用自由函数
- 为
在下面,我将演示所有的方法,最后是一个完整的示例程序,其中包括所有这些选项,并在windows上使用GCC4.5.3(Cygwin)编译
和getId()
烘焙自定义getValues()
actors(完整性)phoenix::function
1.使
结构适应融合序列:项
- 同样,您可以让
规则本身直接使用一个融合序列,而不是项
实例项
error C2825: 'F': must be a class or namespace when followed by '::' 1> c:\path\to\boost\boost/bind/bind_template.hpp(15) : see reference to class template instantiation 'boost::_bi::result_traits<R,F>' being compiled 1> with 1> [ 1> R=boost::_bi::unspecified, 1> F=std::basic_string<char,std::char_traits<char>,std::allocator<char>> (__thiscall Item::* )(void) const 1> ] 1> .\spiritTest.cpp(85) : see reference to class template instantiation 'boost::_bi::bind_t<R,F,L>' being compiled 1> with 1> [ 1> R=boost::_bi::unspecified, 1> F=std::string (__thiscall Item::* )(void) const, 1> L=boost::_bi::list2<boost::_bi::value<boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::reference_eval,boost::fusion::vector<boost::spirit::attribute<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_,boost::fusion::void_>>>>,boost::_bi::value<boost::spirit::_1_type>> 1> ] 1> .\spiritTest.cpp(57) : while compiling class template member function 'list_generator<Iterator>::list_generator(const ItemList &)' 1> with 1> [ 1> Iterator=Iter 1> ] 1> .\spiritTest.cpp(116) : see reference to class template instantiation 'list_generator<Iterator>' being compiled 1> with 1> [ 1> Iterator=Iter 1> ]
BOOST_FUSION_ADAPT_ADT(Item, (std::string, std::string, obj.getId(), (void)val) (Item::Values const&, Item::Values const&, obj.getValues(), (void)val) ) // the rule becomes simply item = lit("<item>") << id // yay for fusion magic! << values << lit("</item>");
item = lit("<item>") << karma::attr_cast<boost::fusion::vector<std::string, Item::Values> > // cast up front ( id // directly << values // ) << lit("</item>");
struct deferredGetId { template<typename,typename,typename> struct result { typedef void type; }; template<typename Attr, typename Ctx, typename Bool> void operator()(Attr& attribute, Ctx const& context, Bool& flag) const { attribute = boost::fusion::at_c<0>(context.attributes).getId(); flag = true; } };
// non-template free function void hardcodedGetId(std::string& attribute, boost::spirit::context<boost::fusion::cons<const Item&, boost::fusion::nil>, boost::fusion::vector0<> > const& context, bool& flag) { attribute = boost::fusion::at_c<0>(context.attributes).getId(); flag = true; }
item = lit("<item>") << id [_1 = phoenix::bind(&Item::getId, _val)] // works fine on GCC :) << id [deferredGetId()] // approach #1 (a) << id [hardcodedGetId] // approach #1 (b) << values[_1 = phoenix::bind(&Item::getValues, _val)] << lit("</item>");
struct GetId { template<typename> struct result { typedef std::string type; }; template<typename Item> std::string operator()(Item const& item) const { return item.getId(); } }; struct GetValues { template<typename> struct result { typedef Item::Values type; }; template<typename Item> typename Item::Values const& operator()(Item const& item) const { return item.getValues(); } }; boost::phoenix::function<GetId> phx_getId; boost::phoenix::function<GetValues> phx_getValues;
item = lit("<item>") << id[_1 = phx_getId(_val)] << values[_1 = phx_getValues(_val)] << lit("</item>");
#include <boost/config/warning_disable.hpp> #include <boost/foreach.hpp> #include <boost/assign/list_of.hpp> #include <boost/range/adaptors.hpp> #include <boost/range/algorithm.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/bind.hpp> #include <iostream> #include <string> #include <list> #include <boost/fusion/adapted.hpp> namespace karma = boost::spirit::karma; namespace spirit = boost::spirit; namespace ascii = boost::spirit::ascii; namespace phoenix = boost::phoenix; class Item { public: typedef std::vector<int> Values; Item(const std::string & i, const Values & v) : m_id(i), m_values(v) {} std::string getId() const { return m_id; } const Values & getValues() const { return m_values; } private: std::string m_id; Values m_values; }; class ItemList { public: typedef std::map<std::string, Item> Items; ItemList() {} ItemList(const Items & s, const Items & o) : m_some(s), m_other(o) {} const Items getSome() const { return m_some; } const Items getOther() const { return m_other; } private: Items m_some;; Items m_other; }; ///////////////////////////////////////////// // 1. Adapting the `Item` struct BOOST_FUSION_ADAPT_ADT(Item, (std::string, std::string, obj.getId(), (void)val) (Item::Values const&, Item::Values const&, obj.getValues(), (void)val) ) ///////////////////////////////////////////// // 2. Precooking Actors struct deferredGetId { template<typename,typename,typename> struct result { typedef void type; }; template<typename Attr, typename Ctx, typename Bool> void operator()(Attr& attribute, Ctx const& context, Bool& flag) const { attribute = boost::fusion::at_c<0>(context.attributes).getId(); flag = true; } }; // non-template free function void hardcodedGetId(std::string& attribute, boost::spirit::context<boost::fusion::cons<const Item&, boost::fusion::nil>, boost::fusion::vector0<> > const& context, bool& flag) { attribute = boost::fusion::at_c<0>(context.attributes).getId(); flag = true; } ///////////////////////////////////////////// // 3. phoenix::function struct GetId { template<typename> struct result { typedef std::string type; }; template<typename Item> std::string operator()(Item const& item) const { return item.getId(); } }; struct GetValues { template<typename> struct result { typedef Item::Values type; }; template<typename Item> typename Item::Values const& operator()(Item const& item) const { return item.getValues(); } }; boost::phoenix::function<GetId> phx_getId; boost::phoenix::function<GetValues> phx_getValues; template <typename Iterator> struct list_generator : karma::grammar<Iterator, ItemList()> { list_generator(const ItemList & i) : list_generator::base_type(start) { using karma::int_; using karma::_1; using karma::lit; using karma::_val; // using phoenix causes: fatal error LNK1179: invalid or corrupt file: // duplicate COMDAT // '?value@?$result_@U?$member_variable@$$A6E?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZP8Item@@AE?AV12@XZ@detail@phoenix@boost@@@?$is_mem_fun_pointer_select@$0A@@detail@boost@@2_NB' // this is probably because the symbol names are too long. // Convert maps into lists containing only the values const Items some = boost::copy_range<Items>(i.getSome() | boost::adaptors::map_values); const Items other = boost::copy_range<Items>(i.getOther() | boost::adaptors::map_values); id = lit("<id>") << karma::string << lit("</id>"); values = lit("<values>") << (int_ % ';') << lit("</values>"); item = lit("<item>") // << id[_1 = phoenix::bind(&Item::getId, _val)] // works fine on GCC :) << id [deferredGetId()] // approach #2 (a) << id [hardcodedGetId] // approach #2 (b) << id [_1= phx_getId(_val)] // approach #3 // << values[_1 = phoenix::bind(&Item::getValues, _val)] << values[_1 = phx_getValues(_val)] << lit("</item>"); item = lit("<item>") << id // approach #1: using BOOST_FUSION_ADAPT_ADT << values // approach #1: using BOOST_FUSION_ADAPT_ADT << lit("</item>"); // approach #2 _with_ attr_cast: item = lit("<item>") << karma::attr_cast<boost::fusion::vector<std::string, Item::Values> > ( id // 'native' fusion sequence access << values // 'native' fusion sequence access ) << lit("</item>"); start = lit("<some>") << (*item)[_1 = some] << lit("</some>") << lit("<other>") << (*item)[_1 = other] << lit("</other>"); } typedef std::vector<Item> Items; karma::rule<Iterator, std::string()> id; karma::rule<Iterator, Item::Values()> values; karma::rule<Iterator, Item()> item; karma::rule<Iterator, ItemList()> start; }; int main() { const Item::Values values = boost::assign::list_of(1)(2)(3); const Item a("a", values); const Item b("b", values); ItemList::Items some, other; some.insert(std::make_pair(a.getId(), a)); other.insert(std::make_pair(b.getId(), b)); const ItemList items(some, ItemList::Items()); typedef std::back_insert_iterator<std::string> Iter; typedef list_generator<Iter> Generator; Generator grammar(items); std::string generated; Iter sink(generated); if (!karma::generate(sink, grammar)) { std::cout << "Generating failed\n"; } else { std::cout << "Generated: " << generated << "\n"; } return 0; }
- 使