2013-08-10 11 views
6

私はboost.spiritのqiライブラリで何かを解析しようとしています。 spirit docsによれば、a >> bはタイプtuple<A, B>のものを生成します。しかしこれはboost::tuple(別名融合ベクター)であり、std::tuple(私が望む)ではありません。boost :: spirit :: qiをstlコンテナを使用するには

この変換を行う簡単な方法はありますかboost::tuple =>std::tuple

同じドキュメントページには、*aは、vector<A>という種類のものが生成されるはずです。これは、std::vector<A>(または暗黙的にstd::vector<A>に変換できる何らかの種類のboost::vector<A>)を生成しているようです。私はこの同じ振る舞いがタプルで利用可能かどうかを知りたかっただけです。

+0

タグ融合と気がBoost.FusionとBoost.Spiritとは関係ありません。 – llonesmiz

+0

whoops、それを解決させてください。 –

答えて

13

短い答え:

使用#include <boost/fusion/adapted/std_tuple.hpp>

MORE COMPLETE ANSWER:

あなたがhere見ることができるように:属性テーブルで

を、我々は唯一のプレースホルダとしてvector<A>tuple<A, B...>を使用します。 vector<A>という表記は、タイプAの要素を保持するSTLコンテナを表し、表記tuple<A, B...>は、A、B、...などの要素を保持するBoost.Fusionシーケンスを表します。 Unusedはunused_typeの略です。

だから、パーサ/ジェネレータを使用すると、ブーストとして(融合配列​​に適合させることができるか、何も(そのような融合::ベクトルまたは融合::リストなど)任意の融合配列を使用することができますtuple<A,B...>の属性を持っている場合:: array、boost :: tuple、std :: pair、std :: tuple、BOOST_FUSION_ADAPT_STRUCTを使用した独自の構造体)。

vector<A>がある場合、要素がペアであれば、std :: vector、std :: list、std :: mapを使用することができます。いくつかのカスタマイズポイント(boost :: spirit :: traitsで少なくともis_container、container_value、およびpush_back_container)を特化している場合は、独自の構造体を使用することもできます。

のstd ::ペア
精神にstd::pairを使用することができるようにするために、あなただけの単一のヘッダを追加する必要があります。

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

のstd ::のタプル
ブースト1.48で開始。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_; 

あなたはBOOST_FUSION_ADAPT_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_; 

1がありますしかし、既知の制限は、あなたがルールに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(','); 

あなた自身の構造体として:あなたの入力のキーが繰り返された場合(あなたはもちろん挿入されるマルチマップのすべてを使用している場合)、最初のものだけがマップに挿入されることにかかわらず、覚えておいてくださいコンテナ
spiritのcustomization pointsを使用すると、属性を扱うときにコンテナとして動作するようにすることもできます。特化する必要がある最小値はis_container,container_valuepush_back_containerです。ここにいくつかの例があります:

最初のものはかなりシンプルです。構造体にstd::vector<int>と互換性のある属性があります。 intが解析されるたびに、それはアキュムレータの合計に加算されます。 herehere( "古い答え"の中で)あまり馬鹿なアプローチを見つけることができます。

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コンテナに格納されます。これを使った例(123

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

ありがとう、本当に徹底的でした。ブックマークしました! –

関連する問題