我需要打印一个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(......)中,而且Epsilon Generator不会消耗任何属性我不确定是否可以访问std :: complex来自它?
答案 0 :(得分:3)
我个人不会将其作为序列进行调整(我不确定你是如何将它作为一个双元素融合序列首先调整的。)
然而,它已经完成,它将不是通用的(因此您将对不同的类型参数使用单独的修改(float
,double
,long double
,boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>>
等)。
这似乎是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() };
}
};
} } }
现在您可以使用任何 std::complex<T>
,并且规则/表达式需要融合序列:
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)