问题描述
请考虑以下程序:
using FooVariant = boost::variant<std::string, int>;
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;
foovar_ = bsk::auto_;
start_ = -foovar_;
}
boost::spirit::karma::rule<OutputIt, FooVariant()> foovar_;
boost::spirit::karma::rule<OutputIt, FooOptional()> start_;
};
int main()
{
FooVariant fv = "foo";
FooOptional fo = fv;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}
如预期的那样,将打印foo
.同样,如果我仅用以下命令初始化fo
:
As expected this will print foo
. Likewise if I initialize fo
simply with:
FooOptional fo;
然后,程序将再次按预期打印任何内容.但是,我不想打印任何内容,而是想打印-
.因此,我将start_
的规则更改为:
Then the program will print nothing, again as expected. But instead of printing nothing, I would like to print -
instead. So, I changed my rule for start_
to:
start_ = (foovar_ | '-');
但这会导致编译错误:
我还注意到,如果删除FooVariant
并改为使FooOptional = boost::optional<int>
并更新生成器,则如果将其传递给未设置的可选参数,则可能会导致崩溃.例如:
I also noticed that if I remove the FooVariant
and instead make FooOptional = boost::optional<int>
and update my generator, I can produce a crash if I pass it an unset optional. For example:
int main()
{
FooOptional fo;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}
这使我相信我在错误地使用可选的世代.正确的方法是什么?
Which leads me to believe I'm using the optional generation incorrectly. What is the right way to do this?
更新
多进行一些调查,我发现了一些有趣的东西.我修改后的代码是:
Investigating a little more I discovered something interesting. My modified code is:
using FooVariant = boost::variant<std::string, int>;
using FooOptional = boost::optional<int>;
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;
foovar_ = bsk::int_;
start_ = (bsk::int_ | '-');
}
boost::spirit::karma::rule<OutputIt, int()> foovar_;
boost::spirit::karma::rule<OutputIt, FooOptional()> start_;
};
int main()
{
FooOptional fo;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}
这可以通过打印-
或整数值(如果已分配)来打印(不在粘贴的代码中).但是,当我将start_
规则更改为此:
This works in that it will print the -
or an integer value if one is assigned (which is not in the code pasted). However when I change my start_
rule to this:
start_ = (foovar_ | '-');
我在使用空值时崩溃.
推荐答案
我同意这似乎不符合您的期望.务实的简化可能是将"Nil"表示为变量元素类型:
I agree that this seems not to work as you'd hope. Maybe a pragmatic simplification is to express "Nil" as a variant element type:
struct Nil final {};
using FooVariant = boost::variant<Nil, std::string, int>;
现在,默认构造的FooVariant
将包含Nil
.规则变成:
Now a default-contructed FooVariant
will contain Nil
. And the rule simply becomes:
start_ = string_ | bsk::int_ | "(unset)";
演示
>
#include <boost/spirit/include/karma.hpp>
struct Nil final {};
using FooVariant = boost::variant<Nil, std::string, int>;
template<typename OutputIt = boost::spirit::ostream_iterator>
struct FooGenerator : boost::spirit::karma::grammar<OutputIt, FooVariant()>
{
FooGenerator()
: FooGenerator::base_type(start_)
{
namespace bsk = boost::spirit::karma;
string_ = '"' << *('\\' << bsk::char_("\\\"") | bsk::print | "\\x" << bsk::right_align(2, '0')[bsk::hex]) << '"';
start_ = string_ | bsk::int_ | "(unset)";
}
boost::spirit::karma::rule<OutputIt, std::string()> string_;
boost::spirit::karma::rule<OutputIt, FooVariant()> start_;
};
int main() {
for (auto fo : { FooVariant{}, {FooVariant{42}}, {FooVariant{"Hello\r\nWorld!"}} }) {
std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}
}
打印
(unset)
42
"Hello\x0d\x0aWorld!"
这篇关于Boost Karma:未设置boost :: optional时生成默认文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!