Boost Karma - 非消耗谓词

2024-01-19

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

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

这样 Karma 将始终选择第一个产品,因此我需要某种谓词来做出决定。提升业力教程 http://www.boost.org/doc/libs/1_55_0/libs/spirit/doc/html/spirit/karma/tutorials/karma_adapted_complex.html附带的解决方案需要将 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 生成器 http://www.boost.org/doc/libs/1_55_0/libs/spirit/doc/html/spirit/karma/reference/auxiliary/eps.html作为谓词

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

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


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

不管它完成了,它都不会是通用的(所以你必须对不同类型的参数使用单独的改编(float, double, long double, boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>> etc.).

这似乎是 Spirit 的工作定制点 http://www.boost.org/doc/libs/1_55_0/libs/spirit/doc/html/spirit/advanced/customize.html:

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<T>具有期望融合序列的规则/表达式:

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

注意如何

  • I used duplicate[] to test for 0.0在发出输出之前
  • 在我使用的另一个分支上omit消耗虚部而不显示任何内容

这是一个完整的演示,住在科里鲁 http://coliru.stacked-crooked.com/a/bccb8b73ba706e6b

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

Output:

(123.0, 4.0)
123.0
(123.0, inf)
nan
(123.0, -1.0)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Boost Karma - 非消耗谓词 的相关文章

随机推荐