提升因果报应-非消耗谓词

Boost Karma - non consuming predicate

本文关键字:谓词 因果报应      更新时间:2023-10-16

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

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

这样因果报应总是会选择第一个结果,所以我需要某种谓词来做出决定。Boost Karma教程附带了该解决方案,该解决方案需要将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适配器中的情况下解决这个问题?

我试图使用因果报应::eps生成器作为谓词

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

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

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

不管怎样,它都不会是通用的(所以你必须对不同类型的参数(floatdoublelong doubleboost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>>等)使用单独的适应

这似乎是Spirit的定制点:的工作

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() };
                }
        };
} } }

现在,您只需使用任何std::complex<T>和期望融合序列的规则/表达式:

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

注意

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

这是一个完整的演示,在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)