2016-07-25 2 views
1

ブースト・スピリットのこの非常に単純なジェネレータの構文を自分で見つけるために、カルマ図書館。私は、文字列では、文字列の前に、文字のように多くの空白を表示したいと思います:シンボルのマッピングされた値の前に文字として空白を多く表示する方法

typedef enum {A, B, C} E; 

class EName : public ka::symbols<E, std::string> 
{ 
public: 
    EName() {add (A,"A") (B,"the B") (C,"a C");} 
}; 

class grm: public ka::grammar<iterator, E()> 
{ 
public: 
    grm():grm::base_type(start) 
    { 
     namespace phx = boost::phoenix; 
     namespace ka = boost::spirit::karma;   
     start = ka::duplicate[ka::repeat(phx::bind(&std::string::size,b))[ka::lit(' ')] << b]; 
    } 
private: 

    ka::rule<iterator,E()> start; 
    EName b; 
}; 

int main(int argc, char * argv[]) 
{ 
    grm g; 
    E e = A; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    generated.clear(); 
    e = B; 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    return 0; 
} 

予想される出力は、このように「A」でと続く次の5行目の空白に続く1個の空白です"the B"( "the B"は5文字の文字列です)。

ka::repeat()[]ジェネレータの引数のコンテキストで変数 "b"にアクセスできない可能性があることを理解しています...代わりにka::_valを試してみました。私は実際には、カルマ、フェニックス、フュージョンの両方で十分な経験を持っておらず、答えへの道筋をつくっていませんが、ドキュメンテーションに必要なすべての情報にアクセスできるでしょう。それゆえ、経験よりもむしろドキュメント(または控除)だけで、私がその答えにどのように来ることができるかについてのヒントをいただきたいと思います。

UPDATE:

私は成功せず、キャストの属性を使用してみました:

start = ka::attr_cast<std::string>(ka::string) << b; 

しかし、どちらも、それはコンパイルん:続い

namespace boost { 
    namespace spirit { 
     namespace traits { 
      template <> 
      struct transform_attribute<const E, std::string, ka::domain> 
      { 
       typedef std::string type; 
       static type pre(const E & e) { 
        EName s; 
        int num = s.find(e)->size(); 
        return std::string(num, ' '); 
       } 
      }; 
} } } 

+0

あなたはブーストを使用してそれを行うには強制はありますか? – Angelos

+0

私の質問です。私はもちろん、それをやることなくやる方法を知っています。 – Heyji

答えて

1

あなたの問題を2つに分けることができます。

  • は、列挙型の値から文字列を取得します。
  • 文字列内には、その文字列内にあるスペースをいくつでも先頭に追加します。

問題の2番目の部分は、right_align directiveを使用するとかなり簡単です。あなたは、単に使用することができます。

prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string]; 

(あなたは、単に空白以外に何か他のものを使用したい場合は)たとえばka::right_align(2*phx::size(ka::_val),ka::lit('*'))[ka::string]用(right_alignするために第2のパラメータを使用することができます)

最初の部分では、あなたが何かを行うことができます表示されているとおりattr_castと入力します。以下のコードでは、シンボルテーブルから文字列を取得するためにphx::bindを使用しました。

Running on WandBox

#include <iostream> 
#include <string> 
#include <vector> 

#include <boost/spirit/include/karma.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

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

typedef enum {A, B, C} E; 

class EName : public ka::symbols<E, std::string> 
{ 
public: 
    EName() {add (A,"A") (B,"the B") (C,"a C");} 
}; 

template <typename Iterator> 
class grm: public ka::grammar<Iterator, E()> 
{ 
public: 
    grm():grm::base_type(start) 
    { 

     prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string]; 
     start = prepend_spaces[ka::_1=phx::bind(&EName::at<E>,phx::ref(name),ka::_val)]; 
    } 
private: 

    ka::rule<Iterator,E()> start; 
    ka::rule<Iterator,std::string()> prepend_spaces; 
    EName name; 
}; 

int main(int argc, char * argv[]) 
{ 
    grm<std::back_insert_iterator<std::string> > g; 
    E e = A; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    generated.clear(); 
    e = B; 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 

    generated.clear(); 
    std::vector<E> v {A,B,C}; 
    ka::generate(sink,+g,v); 
    std::cout << generated << "\n"; 
    return 0; 
} 
+0

ニース。 ka :: _ 1 = phx :: bind(&EName :: at、phx :: ref(name)、ka :: _ val)のような短いパスが必要ですが、動作させることはできません。 – Heyji

+0

[This](http://melpon.org/wandbox/permlink/l8U5r0fasq4fZ08c)は、「attr_cast」が必須ではないように見えるため、「attr_cast」(実際には「transform_attribute」)を使用したアプローチを意味しました。私はこのアプローチが気に入らなかった。なぜなら、特に、カルマとの 'attr_cast'の問題が(現在のバージョンではすでに解決されている)問題の多くを見てきたからです。 – llonesmiz

1

私はそれほど遠くはなかったので、私はここに私の最初の試みを投稿します。その他のソリューションも歓迎されています。

namespace ka = boost::spirit::karma;  

typedef enum {A, B, C} E; 

class EName : public ka::symbols<E, std::string> 
{ 
public: 
    EName() {add (A,"A") (B,"the B") (C,"a C");} 
}; 

namespace boost { 
    namespace spirit { 
     namespace traits { 
      template <> 
      struct transform_attribute<const E, std::string, ka::domain> 
      { 
       typedef std::string type; 
       static type pre(const E & e) { 
        EName s; 
        int num = s.find(e)->size(); 
        return std::string(num, ' '); 
       } 
      }; 
} } } 

class grm: public ka::grammar<iterator, E()> 
{ 
public: 
    grm():grm::base_type(start) 
    {  
     start = ka::duplicate[ka::attr_cast<std::string>(ka::string) << b]; 
    } 
private: 

    ka::rule<iterator,E()> start; 
    EName b; 
}; 

int main(int argc, char * argv[]) 
{ 
    grm g; 
    E e = A; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    generated.clear(); 
    e = B; 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    return 0; 
} 
関連する問題