2011-05-27 5 views
9

मैं QI और फीनिक्स का उपयोग कर रहा है, और मैं एक छोटे से व्याकरण है कि 4 bools जो एक समारोह कॉल एक अर्थ कार्रवाई के अंदर के लिए तर्क के रूप में इस्तेमाल किया जा रहे हैं देता है लिखना चाहते हैं।बूस्ट :: आत्मा :: क्यूई। इनलाइन पर्सर एक्सप्रेशन को स्टैंडअलोन व्याकरण में कैसे बदलें, और उनके द्वारा उत्पन्न टुपल को कैसे अनपैक करें?

मैं कई कार्य है कि उन चीजों की जरूरत है, और अब तक मैं इस दृष्टिकोण का इस्तेमाल किया है:

(qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool) 
[px::bind(&Bool4Function, spirit::_val, spirit::_1, spirit::_2, spirit::_3, spirit::_4)] 

और यह अपने आप पर ठीक है सिर्फ सादा बदसूरत और भ्रामक है, जबकि, जगह यह सब का उपयोग कर, नामस्थान भागों का उपयोग करके भी।

इसलिए मैं एक स्टैंडअलोन व्याकरण में इस अभिव्यक्ति को निकालने के लिए चाहता था।

तो मैं इस कोशिश की (क्रेडिट testbed के लिए ildjarn को जाता है):

///// grammar implementation ///// 
#include <boost/fusion/include/vector10.hpp> 
#include <boost/spirit/include/qi_bool.hpp> 
#include <boost/spirit/include/qi_char_.hpp> 
#include <boost/spirit/include/qi_grammar.hpp> 
#include <boost/spirit/include/qi_operator.hpp> 
#include <boost/spirit/include/qi_rule.hpp> 
#include <boost/spirit/include/qi_string.hpp> 

struct FourBools : boost::spirit::qi::grammar< 
    char const*, 
    boost::fusion::vector4<bool, bool, bool, bool>() 
> 
{ 
    typedef boost::fusion::vector4<bool, bool, bool, bool> attribute_type; 

    FourBools() : base_type(start_) 
    { 
     using boost::spirit::bool_; 

     start_ 
      = "4bools:" 
      >> bool_ >> ',' 
      >> bool_ >> ',' 
      >> bool_ >> ',' 
      >> bool_ >> ';' 
      ; 
    } 

private: 
    boost::spirit::qi::rule< 
     base_type::iterator_type, 
     base_type::sig_type 
    > start_; 
}; 
FourBools const fourBools; 


///// demonstration of use ///// 
#include <string> 
#include <ios> 
#include <iostream> 
#include <boost/fusion/include/at_c.hpp> 
#include <boost/spirit/include/phoenix_bind.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/qi_action.hpp> 
#include <boost/spirit/include/qi_parse.hpp> 



void noDice(bool a, bool b, bool c, bool d) 
{ 

} 

void worksFine(boost::fusion::vector4<bool, bool, bool, bool> a) 
{ 

} 
int main() 
{ 
    namespace phx = boost::phoenix; 
    namespace spirit = boost::spirit; 

    std::string const input("4bools:true,true,true,false;"); 


    char const* first = input.c_str(); 
    char const* const last = first + input.size(); 
    bool const success = spirit::qi::parse(
     first, last, 
     fourBools[phx::bind(&noDice, spirit::_1)] 
    ); 


    if (!success) 
     std::cout << "parse() failed\n"; 
    else if (first != last) 
     std::cout << "didn't consume all input\n"; 
    std::cout.flush(); 
} 

कि जब तक fourBools[phx::bind(&noDice, spirit::_1)] संकलन नहीं है fourBools[phx::bind(&worksFine, spirit::_1)] साथ बदल दिया है।

इसका मतलब है, मेरी समस्या फ़ंक्शन के हस्ताक्षर से मेल खाने के लिए तर्कों का अनपॅकिंग है, क्योंकि तर्कों की संख्या हस्ताक्षर स्तर (चार बूलों का एक टुपल, स्वयं चार बूल बनाम) पर भिन्न होती है।

यह सीधे फोनिक्स प्लेसहोल्डर का उपयोग कर, रैपर जो अपने मौजूदा कार्यों कि जरूरत है उन्हें अलग करने के लिए अलग-अलग तर्क में tuples का अनुवाद लेखन के बजाय खोल करना संभव है? यदि यह है, तो इसके लिए वाक्यविन्यास क्या होगा? सब के बाद, (qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool) की तरह एक इनलाइन संस्करण ठीक काम करता है जब spirit::_1 - spirit::_4, प्लेसहोल्डर द्वारा 'अनपैक किया'।

यह इस संस्करण के साथ-साथ एक टपल वापस लौट आता है के रूप में मेरे लिए दिखाई देता है, और किसी भी तरह एक व्याकरण है कि एक रिटर्न के विपरीत ऊपर दृष्टिकोण के साथ unpackable है, यही कारण है कि।

मैं इससे कैसे निपटूं?

उत्तर

12

यह काफी असंभव अपनी समस्या का निदान करने के लिए यदि आप एक पूर्ण, सुसंगत रेप्रो पोस्ट न करें है; यह एक वाक्यविन्यास त्रुटि हो सकती है, यह #include गुम हो सकता है, जो जानता है ..?

यहाँ एक काम कर प्रदर्शन है; उम्मीद है कि तुम क्या अपने कोड के साथ गलत क्या है यह पता लगाने के लिए एक संदर्भ के रूप में उपयोग कर सकते हैं:

///// grammar implementation ///// 
#include <boost/fusion/include/vector10.hpp> 
#include <boost/spirit/include/qi_bool.hpp> 
#include <boost/spirit/include/qi_char_.hpp> 
#include <boost/spirit/include/qi_grammar.hpp> 
#include <boost/spirit/include/qi_operator.hpp> 
#include <boost/spirit/include/qi_rule.hpp> 
#include <boost/spirit/include/qi_string.hpp> 

struct FourBools : boost::spirit::qi::grammar< 
    char const*, 
    boost::fusion::vector4<bool, bool, bool, bool>() 
> 
{ 
    typedef boost::fusion::vector4<bool, bool, bool, bool> attribute_type; 

    FourBools() : base_type(start_) 
    { 
     using boost::spirit::bool_; 

     start_ 
      = "4bools:" 
       >> bool_ >> ',' 
       >> bool_ >> ',' 
       >> bool_ >> ',' 
       >> bool_ >> ';' 
      ; 
    } 

private: 
    boost::spirit::qi::rule< 
     base_type::iterator_type, 
     base_type::sig_type 
    > start_; 
}; 
FourBools const fourBools; 


///// demonstration of use ///// 
#include <string> 
#include <ios> 
#include <iostream> 
#include <boost/fusion/include/at_c.hpp> 
#include <boost/spirit/include/phoenix_bind.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/qi_action.hpp> 
#include <boost/spirit/include/qi_parse.hpp> 

typedef FourBools::attribute_type attr_t; 

struct verify_same 
{ 
    explicit verify_same(attr_t const& expected) : expected_(expected) { } 

    void verify(attr_t const& actual) const 
    { 
     using boost::fusion::at_c; 

     std::cout << std::boolalpha 
      << "same as expected: " << (actual == expected_) 
      << "\nactual values: " 
      << at_c<0>(actual) << ' ' 
      << at_c<1>(actual) << ' ' 
      << at_c<2>(actual) << ' ' 
      << at_c<3>(actual) << '\n'; 
    } 

private: 
    attr_t expected_; 
}; 

int main() 
{ 
    namespace phx = boost::phoenix; 
    namespace spirit = boost::spirit; 

    std::string const input("4bools:true,true,true,false;"); 
    verify_same const vs(attr_t(true, true, true, false)); 

    char const* first = input.c_str(); 
    char const* const last = first + input.size(); 
    bool const success = spirit::qi::parse(
     first, last, 
     fourBools[phx::bind(&verify_same::verify, phx::cref(vs), spirit::_1)] 
    ); 
    if (!success) 
     std::cout << "parse() failed\n"; 
    else if (first != last) 
     std::cout << "didn't consume all input\n"; 
    std::cout.flush(); 
} 

एक के रूप में अलग रूप में, मैं विशुद्ध रूप से सजातीय प्रकार के साथ एक टपल का उपयोग कर अजीब बात है लगता है; व्यक्तिगत रूप से, मैं व्याकरण की संश्लेषित विशेषता boost::array<bool, 4> में बदल दूंगा।


संपादित (ओ पी के संपादन के जवाब में): अच्छी खबर यह है और बुरी खबर और अधिक अच्छी खबर नहीं है।

यहां अच्छी खबर है: Boost.Fusion में न्यूनतम कोड के साथ आप जो करना चाहते हैं उसे करने की कार्यक्षमता है: boost::fusion::fused<>।यह एक कॉल करने योग्य प्रकार (फ्री-फ़ंक्शन पॉइंटर्स और सदस्य-फ़ंक्शन पॉइंटर्स समेत) लेगा जो कई तर्क लेता है और कॉल करने योग्य प्रकार को उस फ़ंक्शन में ले जाता है जो फ़्यूज़न अनुक्रम लेता है; जब इस मज़ेदार को बुलाया जाता है, तो यह फ़्यूज़न अनुक्रम लेता है और इसे अनपैक्स करता है, लिपले के अलग-अलग तत्वों को लिपटे कॉल करने योग्य प्रकार को अलग तर्क के रूप में अग्रेषित करता है।

तो, व्याकरण मैं पहले से ही तैनात दिया जाता है और निम्नलिखित:

#include <string> 
#include <ios> 
#include <iostream> 
#include <boost/fusion/include/at_c.hpp> 
#include <boost/fusion/include/make_fused.hpp> 
#include <boost/spirit/include/phoenix_bind.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_fusion.hpp> 
#include <boost/spirit/include/qi_action.hpp> 
#include <boost/spirit/include/qi_parse.hpp> 

typedef FourBools::attribute_type attr_t; 

void free_func_taking_tuple(attr_t const& tup) 
{ 
    using boost::fusion::at_c; 

    std::cout << std::boolalpha 
     << "inside free_func_taking_tuple() :: " 
     << at_c<0>(tup) << ' ' 
     << at_c<1>(tup) << ' ' 
     << at_c<2>(tup) << ' ' 
     << at_c<3>(tup) << '\n'; 
} 

void free_func_taking_bools(
    bool const a, bool const b, 
    bool const c, bool const d 
) 
{ 
    std::cout << std::boolalpha 
     << "inside free_func_taking_bools() :: " 
     << a << ' ' 
     << b << ' ' 
     << c << ' ' 
     << d << '\n'; 
} 

boost::spirit::qi::parse() इसलिए की तरह कहा जा सकता है:

namespace phx = boost::phoenix; 
namespace spirit = boost::spirit; 
using boost::fusion::make_fused; 

// calls free_func_taking_tuple, nothing new here 
spirit::qi::parse(
    first, last, 
    fourBools[phx::bind(free_func_taking_tuple, spirit::_1)] 
); 

// calls free_func_taking_bools, using boost::fusion::fused<> to unpack the tuple 
// into separate arguments 
spirit::qi::parse(
    first, last, 
    fourBools[phx::bind(make_fused(&free_func_taking_bools), spirit::_1)] 
); 

यहाँ बुरी खबर है: Boost.Fusion के प्रतिदेय प्रकार के रैपर पर भरोसा करते हैं TR1/C++ 11 result_of प्रोटोकॉल, जबकि Boost.Phoenix v2 Boost.Lambda result_of प्रोटोकॉल लागू करता है – ये संगत नहीं हैं। नतीजतन, आपको अपने आप को ट्यूपल तत्वों को अनपैक करना होगा:

namespace phx = boost::phoenix; 
namespace spirit = boost::spirit; 

spirit::qi::parse(
    first, last, 
    fourBools[phx::bind(
     free_func_taking_bools, 
     phx::at_c<0>(spirit::_1), 
     phx::at_c<1>(spirit::_1), 
     phx::at_c<2>(spirit::_1), 
     phx::at_c<3>(spirit::_1) 
    )] 
); 

यक! लेकिन, और भी अच्छी खबर है: Boost.Phoenix v3 बूस्ट 1.47 में रिलीज़ होने जा रहा है, और यह TR1/C++ 11 result_of प्रोटोकॉल लागू करता है। नतीजतन, बूस्ट 1.47 के साथ शुरू करने से आप boost::fusion::fused<> का उपयोग कर सकेंगे और स्वयं को कुछ कठिन बॉयलरप्लेट बचा सकते हैं।

+0

इस तरह की टिप्पणियां शायद इस पर फंसे हुए हैं, लेकिन मुझे बस अपनी छाती से इस तरह के कोड को देखने के बारे में मेरी इच्छा है। मैं इसके बगल में बहुत गड़बड़ महसूस करता हूं, यह बहुत प्रेरणादायक है, सूचीबद्ध चीजों में से आधे को भी नहीं पता था और मैंने सोचा कि मैं पहले से ही बेहतर हो रहा हूं। वैसे भी, मैं कल एक रिपो शामिल करूंगा, अगर यह अभी भी आपकी पोस्ट का विश्लेषण करने के बाद काम नहीं करेगा। – Erius

+0

@ एरियस: -] यदि आप एक रेपो पोस्ट करना समाप्त करते हैं, तो कृपया इस उत्तर पर एक टिप्पणी पोस्ट करें, इसलिए मुझे अपने एसओ इनबॉक्स में एक संदेश मिलेगा, अन्यथा शायद मैं आपका संपादन नहीं देखूंगा। – ildjarn

+0

हो गया, फिर से धन्यवाद। – Erius

0

qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool की विशेषता std::vector<bool> या किसी अन्य एसटीएल कंटेनर है, जैसा कि संदर्भ में वर्णित है: http://www.boost.org/doc/libs/1_46_0/libs/spirit/doc/html/spirit/qi/quick_reference/compound_attribute_rules.html

तालिका की पहली पंक्ति मामले :)

+0

कोशिश की कि अभी, संकलित नहीं किया गया है, जब तक कि मुझे वेक्टर से मूल्य निकालने के लिए qi :: _ 1 - qi :: _ 4 का उपयोग नहीं करना चाहिए। – Erius

+0

'bool_ >> bool_ की विशेषता 'bool_ >> bool_' वास्तव में' संलयन :: वेक्टर <बूल, बूल, बूल, बूल>'; आत्मा केवल 'some_container ' के उपयोग की अनुमति देने के लिए होती है क्योंकि ट्यूपल पूरी तरह से सजातीय प्रकारों से बना है। इस व्यवहार को आत्मा दस्तावेज़ों में 'विशेषता गिरने' कहा जाता है। – ildjarn

3

एक सामान्य नोट के रूप में, मैं आत्मा वेबसाइट here पर विशेषता प्रबंधन के बारे में लेख पढ़ने का सुझाव दूंगा। ये लाइब्रेरी के साथ वितरित ऑनलाइन दस्तावेज़ों में एक अच्छा परिशिष्ट है।

+0

बुकमार्क किया गया। मैं इसके माध्यम से भी काम करना सुनिश्चित करूँगा, धन्यवाद। – Erius

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