我在另一个答案中告诉过你我会如何处理这个问题:
Boost Karma: generate default text when boost::optional is unset
这不仅避免了这个问题,还简化了AST/数据类型。
现在,既然你强迫我,我就坚持下去。问题产生于以下事实:
foovar_ | '|'
是一个
替代表达式
它以某种方式验证了属性必须是兼容的。在检查期间,假设
-
如果
a
具有属性
attr(a)
和
b
具有属性
attr(b)
然后
-
a | b
应该有
variant<attr(a), attr(b)
它会进行一些逻辑检查(比如
attr(a) == attr(b)
)但不是逻辑检查如果
属性(b)
是
unused_type
那么它应该与
optional<attr(a)>
太多了,而不仅仅是
variant<attr(a), unused_type>
甚至
variant<attr(a)>
.
现在,为什么我没那么感兴趣。所以,你可以这样做
武力
东西。
foovar_ = bsk::int_ | bsk::double_;
fooopt_ = (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_;
start_ = '[' << fooopt_ << ']';
这个
钥匙
将其编码为
替代表达式
. 在这里,我们只是信任
-foovar_
说点什么,还是不说。此外,我们也
bsk::eps(is_initialized_(bsk::_val)) | '*'
含义:如果变量已初始化,则仅此而已,否则,生成
'*'
.
现在,您不需要严格遵守第三条规则,如果您喜欢只写代码,您可以只写:
start_ = '[' << (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_ << ']';
演示
哦,我差点忘了:
struct is_initialized_f {
template<typename T>
bool operator()(boost::optional<T> const& opt) const { return opt.is_initialized(); }
};
boost::phoenix::function<is_initialized_f> is_initialized_;
实现帮助程序Phoenix actor以检查初始化状态。
Live On Coliru
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
using FooVariant = boost::variant<int, double>;
using FooOptional = boost::optional<FooVariant>;
template<typename OutputIt = boost::spirit::ostream_iterator>
struct FooGenerator
: boost::spirit::karma::grammar<OutputIt, FooOptional()>
{
FooGenerator()
: FooGenerator::base_type(start_)
{
namespace bsk = boost::spirit::karma;
namespace phx = boost::phoenix;
foovar_ = bsk::int_ | bsk::double_;
//fooopt_ = (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_;
start_ = '[' << (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_ << ']';
}
private:
struct is_initialized_f {
template<typename T>
bool operator()(boost::optional<T> const& opt) const { return opt.is_initialized(); }
};
boost::phoenix::function<is_initialized_f> is_initialized_;
boost::spirit::karma::rule<OutputIt, FooVariant()> foovar_;
//boost::spirit::karma::rule<OutputIt, FooOptional()> fooopt_;
boost::spirit::karma::rule<OutputIt, FooOptional()> start_;
};
int main()
{
for (FooOptional fop : { FooOptional{}, {FooVariant{123}}, {FooVariant{3.14}} }) {
if (std::cout << boost::spirit::karma::format(FooGenerator<>(), fop))
std::cout << "\n";
else
{
std::cout.clear();
std::cout << "#Error\n";
}
}
}
印刷品
[*]
[123]
[3.14]
¹笑话
我们会得到与“某人忘记了”或“这是一种回归”押韵的非权威答案