1

老实说,我放弃(像我之前的许多其他人一样)自己找到这个仍然非常简单的 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");}
};

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 个空格,后跟“B”(因为“B”是 5 个字符的字符串)。

我知道在ka::repeat()[]生成器的参数的上下文中可能无法访问变量“b”......我尝试ka::_val了但没有成功。实际上,我在业力、凤凰和融合方面都没有足够的经验来构建通往答案的道路,尽管我可能可以访问文档中所有需要的信息。因此,我也希望能得到一些提示,告诉我如何仅通过文档(或通过推论)而不是通过经验得出答案。

更新:

我尝试使用属性转换但没有成功:

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, ' ');
                }
            };
} } }

其次是:

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

但它也没有编译。

4

2 回答 2

1

你的问题可以分为两个:

  • 从枚举值中获取一个字符串。
  • 在该字符串中添加与字符一样多的空格。

right_align问题的第二部分使用指令非常简单。您可以简单地使用:

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

(如果你想使用除了空白之外的其他东西,你可以使用 right_align 的第二个参数(例如ka::right_align(2*phx::size(ka::_val),ka::lit('*'))[ka::string]))

对于第一部分,您可以attr_cast按照您所展示的那样做一些事情。在下面的代码中,我用来phx::bind从符号表中获取字符串。

在 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;
}
于 2016-07-27T07:02:46.620 回答
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;
}
于 2016-07-26T14:45:32.067 回答