Boost Karma:当boost ::可选时,生成默认文本

Boost Karma: generate default text when boost::optional is unset

本文关键字:默认 文本 Karma boost Boost      更新时间:2023-10-16

考虑以下程序:

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

,但这导致汇编错误:

newertive_function.hpp:127:34:错误:没有成员命名 'is_compatible' 'boost :: Spirit ::特质:: compute_compatible_component, int>, boost ::可选,int>>,boost :: Spirit :: Karma :: domain>' 如果(!component_type :: is_compatible(spirit ::特质:: wher(attr_((( ~~~~~~~~~~~~~~~^

我还注意到,如果我删除FooVariant并制作FooOptional = boost::optional<int>并更新发电机,则如果将其传递给未设置的可选元件,我会产生崩溃。例如:

int main()
{
    FooOptional fo;
    std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
}

这使我相信我正在错误地使用可选生成。正确的方法是什么?

update

调查更多,我发现了一些有趣的东西。我修改的代码是:

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)";

demo

活在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{"HellornWorld!"}} }) {
        std::cout << boost::spirit::karma::format(FooGenerator<>(), fo) << std::endl;
    }
}

打印

(unset)
42
"Hellox0dx0aWorld!"