提升::精神::因果报应使用有条件的替代操作符(|)

boost::spirit::karma using the alternatives operator (|) with conditions

本文关键字:操作符 有条件 因果报应 精神 提升      更新时间:2023-10-16

我正试图使用boost::spirit::karma从自己的类Value生成一个字符串,但我遇到了这个问题。我试着把我的问题提炼成一个简单的例子。

我想从以下类的实例中生成一个具有因果报应的字符串:

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生成器的括号(当然不起作用):

eps(value.type() == BoolType)

我试着进入boost::phoenix,但我的大脑似乎还没有为这样的事情做好准备。

请帮帮我!

以下是我的完整示例(编译但不工作):main.cpp

想到的最简单的事情是:使用value_变体(因为Karma非常支持变体)。

在语义动作中使用phoenix绑定将起作用:

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(至少),以避免令人讨厌的意外吗?