Boost Karma:未设置 boost::optional 时生成默认文本
Boost Karma: generate default text when boost::optional is unset
考虑以下程序:
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
:
FooOptional fo;
然后程序将再次按预期打印任何内容。但是我不想打印任何东西,而是打印 -
。因此,我将 start_
的规则更改为:
start_ = (foovar_ | '-');
但这会导致编译错误:
alternative_function.hpp:127:34: error: no member named
'is_compatible' in
'boost::spirit::traits::compute_compatible_component,
int>,
boost::optional, int> >, boost::spirit::karma::domain>'
if (!component_type::is_compatible(spirit::traits::which(attr_)))
~~~~~~~~~~~~~~~~^
我还注意到,如果我删除 FooVariant
而不是制作 FooOptional = boost::optional<int>
并更新我的生成器,如果我向它传递一个未设置的可选项,我可能会导致崩溃。例如:
int main()
{
FooOptional fo;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}
这让我相信我错误地使用了可选代。正确的做法是什么?
更新
进一步调查,我发现了一些有趣的事情。我修改后的代码是:
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_
规则更改为:
start_ = (foovar_ | '-');
我遇到一个空值时崩溃。
我同意这似乎不像您希望的那样有效。也许实用的简化是将 "Nil" 表示为变体元素类型:
struct Nil final {};
using FooVariant = boost::variant<Nil, std::string, int>;
现在默认构造的 FooVariant
将包含 Nil
。规则简单地变成:
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!"
考虑以下程序:
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
:
FooOptional fo;
然后程序将再次按预期打印任何内容。但是我不想打印任何东西,而是打印 -
。因此,我将 start_
的规则更改为:
start_ = (foovar_ | '-');
但这会导致编译错误:
alternative_function.hpp:127:34: error: no member named 'is_compatible' in 'boost::spirit::traits::compute_compatible_component, int>, boost::optional, int> >, boost::spirit::karma::domain>' if (!component_type::is_compatible(spirit::traits::which(attr_))) ~~~~~~~~~~~~~~~~^
我还注意到,如果我删除 FooVariant
而不是制作 FooOptional = boost::optional<int>
并更新我的生成器,如果我向它传递一个未设置的可选项,我可能会导致崩溃。例如:
int main()
{
FooOptional fo;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}
这让我相信我错误地使用了可选代。正确的做法是什么?
更新
进一步调查,我发现了一些有趣的事情。我修改后的代码是:
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_
规则更改为:
start_ = (foovar_ | '-');
我遇到一个空值时崩溃。
我同意这似乎不像您希望的那样有效。也许实用的简化是将 "Nil" 表示为变体元素类型:
struct Nil final {};
using FooVariant = boost::variant<Nil, std::string, int>;
现在默认构造的 FooVariant
将包含 Nil
。规则简单地变成:
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!"