【问题标题】:Generating default value when none is found找不到时生成默认值
【发布时间】:2013-09-02 19:27:00
【问题描述】:

我有一个输入向量,其大小可以介于空元素和 3 个元素之间。我希望生成的字符串始终是由空格分隔的 3 个浮点数,如果向量中没有足够的元素,则使用默认值。到目前为止,我已经设法只输出了向量的内容:

#include <iostream>
#include <iterator>
#include <vector>

#include "boost/spirit/include/karma.hpp"

namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;
typedef std::back_insert_iterator<std::string> BackInsertIt;

int main( int argc, char* argv[] )
{
    std::vector<float> input;
    input.push_back(1.0f);
    input.push_back(2.0f);

    struct TestGram 
        : karma::grammar<BackInsertIt, std::vector<float>(), karma::space_type>
    {
        TestGram() : TestGram::base_type(output)
        {
            using namespace karma;
            floatRule = double_;

            output = repeat(3)[ floatRule ];
        }

        karma::rule<BackInsertIt, std::vector<float>(), karma::space_type> output;
        karma::rule<BackInsertIt, float(), karma::space_type> floatRule;
    } testGram;


    std::string output;
    BackInsertIt sink(output);
    karma::generate_delimited( sink, testGram, karma::space, input );

    std::cout << "Generated: " << output << std::endl;

    std::cout << "Press enter to exit" << std::endl;
    std::cin.get();
    return 0;
}

我尝试将浮动规则修改为:floatRule = double_ | lit(0.0f),但这只会给我带来编译错误。我尝试过的许多其他类似的东西也是如此。

我真的不知道如何让它工作。一些帮助会很棒:)

编辑:只是为了说清楚。如果我有一个包含 2 个元素的向量:1.0 和 2.0,我想生成一个如下所示的字符串:"1.0 2.0 0.0"(最后一个值应该是默认值)。

【问题讨论】:

    标签: c++ boost-spirit boost-spirit-karma


    【解决方案1】:

    不漂亮,但工作:

    #include <iostream>
    #include <iterator>
    #include <vector>
    #define BOOST_SPIRIT_USE_PHOENIX_V3
    #include "boost/spirit/include/karma.hpp"
    #include <boost/spirit/include/phoenix.hpp>
    
    namespace karma = boost::spirit::karma;
    namespace phx = boost::phoenix;
    typedef std::back_insert_iterator<std::string> BackInsertIt;
    
    int main(int argc, char* argv[]) {
      std::vector<float> input;
      input.push_back(1.0f);
      input.push_back(2.0f);
    
      struct TestGram: karma::grammar<BackInsertIt, std::vector<float>(),
          karma::space_type> {
        TestGram()
            : TestGram::base_type(output) {
          using namespace karma;
          floatRule = double_;
    
          output = repeat(phx::bind(&std::vector<float>::size, (karma::_val)))[floatRule]
                << repeat(3 - phx::bind(&std::vector<float>::size, (karma::_val)))[karma::lit("0.0")];
        }
    
        karma::rule<BackInsertIt, std::vector<float>(), karma::space_type> output;
        karma::rule<BackInsertIt, float(), karma::space_type> floatRule;
      } testGram;
    
      std::string output;
      BackInsertIt sink(output);
      karma::generate_delimited(sink, testGram, karma::space, input);
    
      std::cout << "Generated: " << output << std::endl;
    
      return 0;
    }
    

    【讨论】:

    • 我想我想出了一些更可口的东西。但是,我真的认为您的数据类型应该类似于struct Vec3 { float a, b; optional&lt;float&gt; c; };
    • @sehe 我宁愿不更改数据类型,因为它使用的上下文。如果我这样做,我将不得不更改几乎一半的管道..
    【解决方案2】:

    大警告:

    显示的代码有缺陷,要么是由于错误,要么是由于滥用 karma 属性传播(见评论)。

    它调用未定义行为(可能)取消引用输入向量上的end() 迭代器。

    这应该可以工作

        floatRule = double_ | "0.0";
    
        output = -floatRule << -floatRule << -floatRule;
    

    注意,floatRule 应改为接受 optional&lt;float&gt;。看到它Live on Coliru

    小例子:

    #include "boost/spirit/include/karma.hpp"
    
    namespace karma = boost::spirit::karma;
    using It = boost::spirit::ostream_iterator;
    
    int main( int argc, char* argv[] )
    {
        const std::vector<float> input { 1.0f, 2.0f };
    
        using namespace karma;
        rule<It, boost::optional<float>()> floatRule      = double_ | "0.0";
        rule<It, std::vector<float>(), space_type> output = -floatRule << -floatRule << -floatRule;
    
        std::cout << format_delimited(output, space, input);
    }
    

    【讨论】:

    • 不幸的是,VS2012 不喜欢您的解决方案。我收到一个安全警告(我可以通过设置 -D_SCL_SECURE_NO_WARNINGS 来禁用它以使其编译,但我宁愿不这样做,因为我不知道这样做可能会掩盖哪些其他错误)。错误是:error C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe
    • 这意味着它不能静态检查迭代器到一个函数/不使用检查(SCARY?)迭代器。它可能是矢量迭代器,或者更有可能是 "0.0"(尝试使用 lit("0.0")?或者,禁用 DEBUG 构建。(我没有 MSVC)
    • 禁用 DEBUG 构建确实可以编译,但输出是一个笑脸而不是 3 个浮点数(不是在开玩笑)。在将您的示例改编为我的代码时,我可能做错了其他事情,但这没关系。我将继续使用 Mike 的“丑陋”代码。无论如何,感谢您的努力;)
    • @Krienie 我刚刚用 VS2010 测试了这个,你是对的。 MSVC 正确地标记了无效的迭代器。我有点敬畏。我刚刚用 valgrind 进行了验证,确实,是向量的迭代器导致了问题。我只能说,我的解决方案只是因为 UB 而“似乎有效”。无论这是否是 Karma 中的错误,我都愿意暂时忘记。
    猜你喜欢
    • 1970-01-01
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    相关资源
    最近更新 更多