2013-08-10 8 views
6

मैं boost.spirit की qi लाइब्रेरी के साथ कुछ पार्स करने की कोशिश कर रहा हूं, और मैं एक समस्या में भाग रहा हूं। spirit docs के अनुसार, a >> b को tuple<A, B> के साथ कुछ उत्पादित करना चाहिए। लेकिन यह boost::tuple (उर्फ फ़्यूज़न वेक्टर) है, और std::tuple (जो मैं चाहता हूं) नहीं है।बढ़ावा देना :: भावना :: qi stl कंटेनर का उपयोग करने के लिए

boost::tuple =>std::tuple के बीच इस रूपांतरण को बनाने का कोई आसान तरीका है?

एक ही प्रलेखन पृष्ठ का कहना है कि *a को vector<A> प्रकार के साथ कुछ प्रस्तुत करना चाहिए। ऐसा लगता है कि यह std::vector<A> (या किसी प्रकार का boost::vector<A> है जो स्पष्ट रूप से std::vector<A> में परिवर्तित हो सकता है) का उत्पादन कर रहा है। मैं सिर्फ यह जानना चाहता था कि यह वही व्यवहार tuples के लिए उपलब्ध था या नहीं।

+0

टैग संलयन और क्यूई में परीक्षण Boost.Fusion और Boost.Spirit से संबंधित नहीं हैं। – llonesmiz

+0

वूप्स, मुझे –

उत्तर

13

संक्षिप्त उत्तर:

उपयोग #include <boost/fusion/adapted/std_tuple.hpp>

अधिक पूरा जवाब:

आप here देख सकते हैं:

विशेषता तालिकाओं में, हम vector<A> और tuple<A, B...> केवल प्लेसहोल्डर के रूप में प्रयोग करेंगे। vector<A> का संकेत किसी प्रकार के एसटीएल कंटेनर होल्डिंग तत्वों के लिए खड़ा है और नोटेशन tuple<A, B...> किसी बूस्ट के लिए खड़ा है। फ़्यूज़न अनुक्रम ए, बी, ... आदि तत्वों को धारण करता है। अंत में, अप्रयुक्त _type के लिए अप्रयुक्त है।

तो जब एक पार्सर/जनरेटर tuple<A,B...> की एक विशेषता आप किसी भी संलयन अनुक्रम या कुछ भी है कि (जैसे बढ़ावा के रूप में एक संलयन अनुक्रम अनुकूलित किया जा सकता है (जैसे कि संलयन :: वेक्टर या संलयन :: सूची के रूप में) का उपयोग कर सकते है :: सरणी, boost :: tuple, std :: pair, std :: tuple, BOOST_FUSION_ADAPT_STRUCT का उपयोग करके अपनी स्वयं की संरचना)।

और जब vector<A> है तो आप std :: vector, std :: list, और यहां तक ​​कि std :: मानचित्र का उपयोग कर सकते हैं यदि आपके तत्व जोड़े हैं। यदि आप कई अनुकूलन बिंदुओं (कम से कम is_container, कंटेनर_वैल्यू और push_back_container को बढ़ावा :: भावना :: लक्षणों में भी विशेषज्ञ हैं) तो आप अपनी खुद की संरचना का भी उपयोग कर सकते हैं।

std :: जोड़ी
आदेश में भावना के साथ std::pair उपयोग करने के लिए आपको बस एक ही शीर्ष लेख जोड़ने की जरूरत है सक्षम होने के लिए: बढ़ावा 1.48 के साथ शुरू

#include <boost/fusion/include/std_pair.hpp> 
... 
qi::rule<Iterator,std::pair<int,double>()> rule = 
    qi::int_ >> qi::lit(',') >> qi::double_; 

std :: टपल
।0 आप std :: टपल के लिए एक ही कर सकते हैं:

#include <boost/fusion/adapted/std_tuple.hpp> 
... 
qi::rule<Iterator,std::tuple<int,std::string,double>()> rule = 
    qi::int_ >> qi::lit(',') >> +~qi::char_(',') >> qi::lit(',') >> qi::double_; 

आपका अपना struct
आप BOOST_FUSION_ADAPT_STRUCT की मदद से बहुत आसानी से अपने कस्टम struct अनुकूलित कर सकते हैं:

#include <boost/fusion/include/adapt_struct.hpp> 
... 
struct normal_struct 
{ 
    int integer; 
    double real; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    normal_struct, 
    (int, integer) 
    (double, real) 
) 
... 
qi::rule<Iterator,normal_struct()> rule = 
    qi::int_ >> qi::lit(',') >> qi::double_; 

वहाँ एक है ज्ञात सीमा हालांकि, जब आप किसी ऐसे तत्व का उपयोग करने का प्रयास करते हैं जिसमें एक तत्व होता है जो एक कंटेनर संकलन भी विफल रहता है जब तक कि आप अपने नियम में qi::eps >> ... जोड़ते हैं।

struct struct_with_single_element_container 
{ 
    std::vector<int> cont; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    struct_with_single_element_container, 
    (std::vector<int>, cont) 
) 
... 
qi::rule<Iterator,struct_with_single_element_container()> rule = 
    qi::eps >> qi::int_%qi::lit(','); 

std :: नक्शा
आप बस std :: जोड़े की एक कंटेनर के रूप में std :: मानचित्र का उपयोग कर सकते हैं। ध्यान रखें कि हालांकि यदि आपके इनपुट में कुंजी दोहराया जाता है, केवल पहले एक नक्शा करने के लिए सम्मिलित किया जाएगा (यदि आप मल्टीमैप सब कुछ निश्चित रूप से सम्मिलित किया जाएगा का उपयोग करें):

#include <boost/fusion/include/std_pair.hpp> 
... 
qi::rule<std::string::const_iterator, std::pair<double,int>()> pair_rule = 
    qi::double_ >> qi::lit('=') >> qi::int_; 
qi::rule<std::string::const_iterator, std::map<double,int>()> rule = 
    pair_rule%qi::lit(','); 
//You can also use 
//qi::rule<std::string::const_iterator, std::map<double,int>()> rule = 
    //(qi::double_ >> qi::lit('=') >> qi::int_)%qi::lit(','); 

आपका अपना struct एक के रूप में कंटेनर
भावना का customization points का उपयोग करके आप अपनी संरचना को व्यवहार के साथ व्यवहार करते समय कंटेनर के रूप में व्यवहार कर सकते हैं। कम से कम आपको विशेषज्ञता देने की आवश्यकता है is_container, container_value और push_back_container। यहां कुछ उदाहरण दिए गए हैं:


पहला वाला सरल (और मूर्ख) है। यह आपकी संरचना को std::vector<int> के साथ संगत विशेषता प्रदान करता है। हर बार जब एक int पार्स किया जाता है तो यह कुल मिलाकर जमाकर्ता में जोड़ा जाता है। आप कम मूर्ख दृष्टिकोण here और here ("पुराने उत्तर" में) पा सकते हैं।

struct accumulator 
{ 
    accumulator(): total(){} 
    int total; 
}; 

namespace boost{ namespace spirit{ namespace traits 
{ 
    template<> 
    struct is_container<accumulator> : boost::mpl::true_ 
    {}; 

    template<> 
    struct container_value<accumulator> 
    { 
     typedef int type; 
    }; 

    template<> 
    struct push_back_container<accumulator,int> 
    { 
     static bool call(accumulator& c, int val) 
     { 
      c.total+=val; 
      return true; 
     } 
    }; 
}}} 
... 
qi::rule<Iterator,accumulator()> rule = 
    qi::int_%qi::lit(','); 

दूसरा एक (बहुत ज्यादा नहीं) एक छोटे से अधिक जटिल है। यह आपकी संरचना को std::vector<boost::variant<int,std::string> > के साथ संगत विशेषता प्रदान करता है। जब किसी int को पार्स किया जाता है तो इसे वितरक में ints कंटेनर में जोड़ा जाता है, इसी प्रकार तारों को strings कंटेनर में संग्रहीत किया जाता है। इसका उपयोग करने वाले उदाहरण (1, 2 और 3)।

struct distributor 
{ 
    distributor():ints(),strings(){} 
    std::vector<int> ints; 
    std::vector<std::string> strings; 
}; 

namespace boost{ namespace spirit{ namespace traits 
{ 
    template<> 
    struct is_container<distributor> : boost::mpl::true_ 
    {}; 

    template<> 
    struct container_value<distributor> 
    { 
     typedef boost::variant<int,std::string> type; 
    }; 

    template<> 
    struct push_back_container<distributor,int> 
    { 
     static bool call(distributor& c, int val) 
     { 
      c.ints.push_back(val); 
      return true; 
     } 
    }; 

    template<> 
    struct push_back_container<distributor,std::string> 
    { 
     static bool call(distributor& c, std::string const& val) 
     { 
      c.strings.push_back(val); 
      return true; 
     } 
    }; 
}}} 
... 
qi::rule<std::string::const_iterator, std::string()> string_rule = 
    +~qi::char_(','); 
qi::rule<std::string::const_iterator, distributor()> rule = 
    (qi::int_ | string_rule)%qi::lit(','); 

भी सिर्फ़ एक ही cpp फ़ाइल

#include <iostream> 
#include <string> 
#include <utility> 
#include <tuple> 
#include <list> 
#include <vector> 
#include <map> 

#include <boost/fusion/include/std_pair.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/fusion/adapted/std_tuple.hpp> 

#include <boost/spirit/include/qi.hpp> 

#include <boost/variant.hpp> 

namespace qi=boost::spirit::qi; 

struct normal_struct 
{ 
    int integer; 
    double real; 
}; 

struct struct_with_single_element_container 
{ 
    std::vector<int> cont; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    normal_struct, 
    (int, integer) 
    (double, real) 
) 

BOOST_FUSION_ADAPT_STRUCT(
    struct_with_single_element_container, 
    (std::vector<int>, cont) 
) 

struct accumulator 
{ 
    accumulator(): total(){} 
    int total; 
}; 

namespace boost{ namespace spirit{ namespace traits 
{ 
    template<> 
    struct is_container<accumulator> : boost::mpl::true_ 
    {}; 

    template<> 
    struct container_value<accumulator> 
    { 
     typedef int type; 
    }; 

    template<> 
    struct push_back_container<accumulator,int> 
    { 
     static bool call(accumulator& c, int val) 
     { 
      c.total+=val; 
      return true; 
     } 
    }; 
}}} 

struct distributor 
{ 
    distributor():ints(),strings(){} 
    std::vector<int> ints; 
    std::vector<std::string> strings; 
}; 

namespace boost{ namespace spirit{ namespace traits 
{ 
    template<> 
    struct is_container<distributor> : boost::mpl::true_ 
    {}; 

    template<> 
    struct container_value<distributor> 
    { 
     typedef boost::variant<int,std::string> type; 
    }; 

    template<> 
    struct push_back_container<distributor,int> 
    { 
     static bool call(distributor& c, int val) 
     { 
      c.ints.push_back(val); 
      return true; 
     } 
    }; 

    template<> 
    struct push_back_container<distributor,std::string> 
    { 
     static bool call(distributor& c, std::string const& val) 
     { 
      c.strings.push_back(val); 
      return true; 
     } 
    }; 
}}} 


int main() 
{ 
    { 
     std::pair<int,double> parsed; 
     qi::rule<std::string::const_iterator, std::pair<int,double>()> rule = 
        qi::int_ >> qi::lit(',') >> qi::double_; 
     std::string test="1,2.5"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "First: " << parsed.first << ", Second: " << parsed.second << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     std::tuple<int,std::string,double> parsed; 
     qi::rule<std::string::const_iterator, std::tuple<int,std::string,double>()> rule = 
        qi::int_ >> qi::lit(',') >> +~qi::char_(',') >> qi::lit(',') >> qi::double_; 
     std::string test="1,abc,2.5"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "get<0>: " << std::get<0>(parsed) << ", get<1>: " << std::get<1>(parsed) << ", get<2>: " << std::get<2>(parsed) << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     normal_struct parsed; 
     qi::rule<std::string::const_iterator, normal_struct()> rule = 
        qi::int_ >> qi::lit(',') >> qi::double_; 
     std::string test="1,2.5"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "integer: " << parsed.integer << ", real: " << parsed.real << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     struct_with_single_element_container parsed; 
     //there is a problem when you have a struct with a single element container, the workaround is simply adding qi::eps to the rule 
     qi::rule<std::string::const_iterator, struct_with_single_element_container()> rule = 
        qi::eps >> qi::int_%qi::lit(','); 
     std::string test="1,2"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "[0]: " << parsed.cont[0] << ", [1]: " << parsed.cont[1] << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     std::list<int> parsed; 
     qi::rule<std::string::const_iterator, std::list<int>()> rule = 
        qi::int_%qi::lit(','); 
     std::string test="1,2"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "front: " << parsed.front() << ", back: " << parsed.back() << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     std::map<double,int> parsed; 
     qi::rule<std::string::const_iterator, std::pair<double,int>()> pair_rule = 
        qi::double_ >> qi::lit('=') >> qi::int_; 
     qi::rule<std::string::const_iterator, std::map<double,int>()> rule = 
        pair_rule%qi::lit(','); 
     std::string test="2.5=1,3.5=2"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "map[2.5]: " << parsed[2.5] << ", map[3.5]: " << parsed[3.5] << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     accumulator parsed; 
     qi::rule<std::string::const_iterator, accumulator()> rule = 
        qi::int_%qi::lit(','); 
     std::string test="1,2,3"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "total: " << parsed.total << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

    { 
     distributor parsed; 
     qi::rule<std::string::const_iterator, std::string()> string_rule = 
        +~qi::char_(','); 
     qi::rule<std::string::const_iterator, distributor()> rule = 
        (qi::int_ | string_rule)%qi::lit(','); 
     std::string test="abc,1,2,def,ghi,3,jkl"; 
     std::string::const_iterator iter=test.begin(), end=test.end(); 
     bool result = qi::parse(iter,end,rule,parsed); 
     if(result && iter==end) 
     { 
      std::cout << "Success." << std::endl; 
      std::cout << "ints" << std::endl; 
      for(auto val: parsed.ints) 
       std::cout << val << std::endl; 
      std::cout << "strings" << std::endl; 
      for(const auto& val: parsed.strings) 
       std::cout << val << std::endl; 
     } 
     else 
     { 
      std::cout << "Failure." << std::endl; 
      std::cout << "Unparsed: " << std::string(iter,end) << std::endl; 
     } 
    } 

} 
+0

को ठीक करने दें और भावी विशेषता प्रचार प्रश्नों के लिए पसंदीदा – sehe

+0

धन्यवाद, यह वास्तव में पूरी तरह से था। बुकमार्क! –

संबंधित मुद्दे