考虑以下计划:
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:错误:没有成员命名 'is_compatible'中 “的boost ::精神::特点:: compute_compatible_component, INT&gt;中 boost :: optional,int&gt; &gt;,boost :: spirit :: karma :: domain&gt;' 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_ | '-');
我的空值崩溃了。
答案 0 :(得分:2)
我同意这似乎不会像你一样希望工作。也许实用的简化是表达&#34; Nil&#34;作为变体元素类型:
struct Nil final {};
using FooVariant = boost::variant<Nil, std::string, int>;
现在默认构建的FooVariant
将包含Nil
。规则只会变成:
start_ = string_ | bsk::int_ | "(unset)";
<强> Live On Wandbox 强>
#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!"