C++ 使用boost::spirit::karma生成时如何避免boost::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”:后跟“:”时必须是类或命名空间 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 名称空间业力=提升::精神::业力;

我是错误“LNK1179:无效或损坏的文件:重复COMDAT”的受害者 并让我相信,通过不使用phoenix,我可以避免这个错误

(这是一项后续行动。) 我想用其他东西来取代
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(完整性)

  • 在下面,我将演示所有的方法,最后是一个完整的示例程序,其中包括所有这些选项,并在windows上使用GCC4.5.3(Cygwin)编译


    1.使
    结构适应融合序列:
    • 同样,您可以让
      规则本身直接使用一个融合序列,而不是
      实例。这肯定会从解析器表达式中删除所有绑定/代理复杂性,但是需要更多的工作才能让其余生成器连接起来
    2.对参与者进行“预编译”,以便在语义操作中使用,或者
    • 使用多态函数对象(也称为延迟可调用对象):

      这样,您就可以像这样简单地使用:

      item =
          lit("<item>")
          << id[_1 = phx_getId(_val)]
          << values[_1 = phx_getValues(_val)]
          << lit("</item>");
      
      项目=
      亮(“”)
      
      不能将
      boost::bind
      表达式用作phoenix actor

      关于长时间损坏的名称,如果使用其他TMP繁重的库(例如Boost Range,它有自己的模板实例化森林,从适配器返回视图等),我不会感到惊讶

      你可以试试

    • 使
      结构适应融合序列:(带或不带
      属性转换

      • 同样,您可以让
        规则本身直接使用一个融合序列
    • 要“预编译”角色以用于语义操作,请执行以下操作:

      • 使用多态函数对象(也称为延迟可调用对象)
      • 或者使用自由函数
    • getId()
      getValues()
      烘焙自定义
      phoenix::function
      actors(完整性)

    • 在下面,我将演示所有的方法,最后是一个完整的示例程序,其中包括所有这些选项,并在windows上使用GCC4.5.3(Cygwin)编译


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