我正在尝试使用Value
从我自己的类boost::spirit::karma
生成一个字符串,但我对此感到困惑。我试图将我的问题提取到一个简单的例子中。
我想从以下类的实例生成一个带有karma的String:
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_);
我无法用sth填充eps生成器的括号。像这样(当然不行):
eps(value.type() == BoolType)
我试图进入boost::phoenix
,但我的大脑似乎还没准备好做这样的事情。
请帮助我!
这是我的完整示例(编译但不工作): main.cpp
答案 0 :(得分:3)
最简单的想法是:使用value_
变体(因为Karma非常支持变体)。
在语义动作中使用phoenix bind会起作用:
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
(至少),以避免令人讨厌的意外吗?