【问题标题】:Boost Karma: generate default text when boost::optional is unsetBoost Karma:未设置 boost::optional 时生成默认文本
【发布时间】:2018-07-18 04:11:45
【问题描述】:

考虑以下程序:

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::spirit::traits::compute_compatible_component, 整数>, boost::optional, int> >, boost::spirit::karma::domain>' if (!component_type::is_compatible(spirit::traits::which(attr_))) ~~~~~~~~~~~~~~~~^^

我还注意到,如果我删除 FooVariant 并改为创建 FooOptional = boost::optional&lt;int&gt; 并更新我的生成器,如果我传递一个未设置的选项,我可能会导致崩溃。例如:

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

我因空值而崩溃。

【问题讨论】:

    标签: c++ boost boost-spirit


    【解决方案1】:

    我同意这似乎不像您希望的那样工作。也许务实的简化是将“Nil”表示为变体元素类型:

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

    【讨论】:

    • 不幸的是,这对我来说不是一个可行的选择,因为我坚持使用 boost::optional&lt;boost::variant&lt;...&gt;&gt; 模式。
    • 附带问题,start_ 中的规则顺序重要吗?我的印象是(很可能是错误的)第一个子规则对应于变体中的第一个类型可能性,然后是第二个等等(换句话说,我会写:start_ = "(unset)" | string_ | bsk::int_) .但是你的代码不遵循这种模式,所以我猜顺序并不重要,Karma/C++ 会选择最有效的规则?
    • 顺序并不重要,除非一个分支可能同时满足多个属性类型。我很难想出一个例子,所以也许它不适用于精神的业力方面。关键是属性兼容性规则是基于类型的
    • 我已经能够将此问题简化为与可选和变体更相关的类似问题。我将发布另一个问题,因为您的回答确实解决了这里的问题。
    • 哦,是的,我遇到了问题。我只是很少有动力去努力克服障碍:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 2022-09-28
    • 2018-05-05
    • 1970-01-01
    相关资源
    最近更新 更多