boost :: spirit :: karma используя оператор альтернатив (|) с условиями

Я пытаюсь сгенерировать строку из моего собственного класса с именем Value с помощью boost::spirit::karma, но я застрял с этим. Я попытался извлечь свою проблему в простой пример.

Я хочу создать строку с кармой из экземпляров следующего класса:

class Value
{
public:

enum ValueType
{
BoolType,
NumericType
};

Value(bool b) : type_(BoolType), value_(b) {}
Value(const double d) : type_(NumericType), value_(d) {};

ValueType type() { return type_; }

operator bool() { return boost::get<bool>(value_); }
operator double() { return boost::get<double>(value_); }

private:
ValueType type_;
boost::variant<bool, double> value_;

};

Здесь вы можете увидеть, что я пытаюсь сделать:

int main()
{
using karma::bool_;
using karma::double_;
using karma::rule;
using karma::eps;

std::string generated;
std::back_insert_iterator<std::string> sink(generated);

rule<std::back_insert_iterator<std::string>, Value()> value_rule = bool_ | double_;

Value bool_value = Value(true);
Value double_value = Value(5.0);

karma::generate(sink, value_rule, bool_value);
std::cout << generated << "\n";

generated.clear();

karma::generate(sink, value_rule, double_value);
std::cout << generated << "\n";

return 0;
}

Первый звонок karma::generate() работает нормально, потому что значение — bool, и первый генератор в моем правиле также «потребляет» bool. Но второе karma::generate() не удается с boost::bad_get потому что карма пытается съесть бул и зовет поэтому Value::operator bool(),

Моей следующей мыслью было изменить правило моего генератора и использовать eps() генератор вместе с условием, но здесь я застрял:

value_rule = (eps( ... ) << bool_) | (eps( ... ) << double_);

Я не могу заполнить скобки генератора eps с помощью sth. вот так (конечно не работает):

eps(value.type() == BoolType)

Я пытался попасть в boost::phoenixНо мой мозг, похоже, не готов к таким вещам.

Пожалуйста, помогите мне!

Вот мой полный пример (компиляция, но не работает):
main.cpp

2

Решение

Самое простое, что приходит в голову: использовать value_ вариант (так как варианты очень хорошо поддерживаются кармой).

Использование привязки феникса внутри семантического действия будет работать:

rule<std::back_insert_iterator<std::string>, Value()> value_rule;

value_rule = (bool_ | double_)
[ _1 = phx::bind(&Value::value_, _val) ];

Хотя это требует разоблачения value_друзья Например, вы можете предпочесть метод доступа.

Вот рабочий пример http://liveworkspace.org/code/22ab2093ad9bd3b03e55a7f3dde952f8

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

#include <iostream>
#include <string>

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

class Value
{
public:

enum ValueType
{
BoolType,
NumericType
};

Value(bool b) : type_(BoolType), value_(b) {}
Value(double d) : type_(NumericType), value_(d) {};

ValueType type() { return type_; }

operator bool()   { return boost::get<bool>(value_);   }
operator double() { return boost::get<double>(value_); }

private:
ValueType type_;

friend int main();
boost::variant<bool, double> value_;
};

namespace karma = boost::spirit::karma;

int main()
{
using namespace karma;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);

rule<std::back_insert_iterator<std::string>, Value()> value_rule;

value_rule = (bool_ | double_)
[ _1 = phx::bind(&Value::value_, _val) ];

Value bool_value = Value(true);
Value double_value = Value(5.0);

karma::generate(sink, value_rule, bool_value);
std::cout << generated << "\n";

generated.clear();
karma::generate(sink, value_rule, double_value);
std::cout << generated << "\n";

return 0;
}

Выход

true
5.0

Не по теме: могу ли я предложить маркировку операторы преобразования explicit (по крайней мере), чтобы избежать неприятных сюрпризов?

3

Другие решения

Других решений пока нет …