【问题标题】:Boost Karma - non consuming predicateBoost Karma - 非消费谓词
【发布时间】:2014-04-15 09:06:06
【问题描述】:

我需要打印一个 std::complex 但如果它等于零则省略虚部。所以我有两个产品的规则:

karma::rule<OutputIterator, std::complex<double>()> complexRule = 
    '(' << double_ << ", " double_ << ')'
    | double_ << omit[double_];

这样,Karma 总是会选择第一个产生式,所以我需要某种谓词来做出决定。 Boost Karma tutorial 附带的解决方案需要将 std::complex 改编为三元素元组。

BOOST_FUSION_ADAPT_ADT(
    std::complex<double>,
    (bool, bool, obj.imag() != 0, /**/)
    (double, double, obj.real(), /**/)
    (double, double, obj.imag(), /**/)
)

但不幸的是我不能这样做,因为其他代码正在使用 std::complex 改编为两个元素元组。有没有办法在不直接将谓词添加到 Fusion 适配器的情况下解决该问题?

我试图使用karma::eps generator 作为谓词

auto rule = eps( ... ) << '(' << double_ << ", " << double_ << ')'
          | double_ << omit[double_];

但我不知道应该在 eps(...) 中放入什么 Phoenix 表达式,并且由于 Epsilon Generator 不消耗任何属性,我不确定是否可以从中访问 std::complex ?

【问题讨论】:

    标签: c++ boost boost-spirit boost-spirit-karma


    【解决方案1】:

    我个人不会将其改编为序列(我不确定您最初是如何将其改编为二元素融合序列的)。

    无论如何,它都不会是通用的(因此您将对不同类型的参数(floatdoublelong doubleboost::multiprecision::number&lt;boost::multiprecision::cpp_dec_float&lt;50&gt;&gt; 等)使用单独的适配。

    这似乎是 Spirit customization points 的工作:

    namespace boost { namespace spirit { namespace traits {
    
        template <typename T>
            struct extract_from_attribute<typename std::complex<T>, boost::fusion::vector2<T, T>, void>
            {
                typedef boost::fusion::vector2<T,T> type;
    
                template <typename Context>
                    static type call(std::complex<T> const& attr, Context& context)
                    {
                        return { attr.real(), attr.imag() };
                    }
            };
    
    } } }
    

    现在您可以将 any std::complex&lt;T&gt; 与期望融合序列的规则/表达式一起使用:

     rule = 
            '(' << karma::double_ << ", " << karma::duplicate [ !karma::double_(0.0) << karma::double_ ] << ')' 
          | karma::double_ << karma::omit [ karma::double_ ];
    

    注意方法

    • 在发出输出之前,我使用duplicate[]0.0 进行测试
    • 在另一个分支上,我使用omit 消耗虚部而不显示任何内容

    这是一个完整的演示,Live On Coliru

    #include <boost/spirit/include/karma.hpp>
    #include <complex>
    
    namespace boost { namespace spirit { namespace traits {
    
        template <typename T>
            struct extract_from_attribute<typename std::complex<T>, boost::fusion::vector2<T, T>, void>
            {
                typedef boost::fusion::vector2<T,T> type;
    
                template <typename Context>
                    static type call(std::complex<T> const& attr, Context& context)
                    {
                        return { attr.real(), attr.imag() };
                    }
            };
    
    } } }
    
    namespace karma = boost::spirit::karma;
    
    int main()
    {
        karma::rule<boost::spirit::ostream_iterator, boost::fusion::vector2<double, double>()> 
            static const rule = 
                                '(' << karma::double_ << ", " << karma::duplicate [ !karma::double_(0.0) << karma::double_ ] << ')' 
                              | karma::double_ << karma::omit [ karma::double_ ];
    
        std::vector<std::complex<double>> const values {
                    { 123, 4 },
                    { 123, 0 },
                    { 123, std::numeric_limits<double>::infinity() },
                    { std::numeric_limits<double>::quiet_NaN(), 0 },
                    { 123, -1 },
                };
    
        std::cout << karma::format_delimited(*rule, '\n', values);
    }
    

    输出:

    (123.0, 4.0)
    123.0
    (123.0, inf)
    nan
    (123.0, -1.0)
    

    【讨论】:

    • 非常感谢! karma::duplicate 解决了这个问题。还有关于使用自定义点的好建议,似乎绝对值得一看。
    猜你喜欢
    • 1970-01-01
    • 2016-11-08
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 2017-05-15
    相关资源
    最近更新 更多