Я пытаюсь сгенерировать строку из моего собственного класса с именем 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
Самое простое, что приходит в голову: использовать 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
(по крайней мере), чтобы избежать неприятных сюрпризов?
Других решений пока нет …