Boost Karma:未设置boost :: optional时生成默认文本 [英] Boost Karma: generate default text when boost::optional is unset

查看:122
本文介绍了Boost Karma:未设置boost :: optional时生成默认文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下程序:

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_ | '-');

但这会导致编译错误:

alternative_function.hpp:127:34:错误:未命名成员 'is_compatible'在 'boost :: spirit :: traits :: compute_compatible_component, int>, boost :: optional,int>>,boost :: spirit :: karma :: domain>' 如果(!component_type :: is_compatible(spirit :: traits :: which(attr_))) ~~~~~~~~~~~~~~~~ ^

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>并更新生成器,则如果将其传递给未设置的可选参数,则可能会导致崩溃.例如:

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时生成默认文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆