Boost Karma:当boost :: optional未设置时生成默认文本

时间:2018-02-07 18:43:27

标签: c++ boost boost-spirit

考虑以下计划:

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

我的空值崩溃了。

1 个答案:

答案 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!"