2013-09-02 2 views
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), но только дал мне ошибки компиляции. То же самое для многих других подобных вещей, которые я пробовал.

Я действительно не знаю, как это сделать. Некоторая помощь была бы замечательной :)

EDIT: Просто, чтобы прояснить ситуацию. Если у меня есть вектор, содержащий 2 элемента: 1.0 и 2.0, я хочу сгенерировать строку, которая выглядит так: "1.0 2.0 0.0" (последнее значение должно быть значением по умолчанию).

ответ

2

Не очень, но работа:

#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; 
} 
+0

Да, это сделал трюк. Большое спасибо :) – Krienie

+0

Я думаю, что придумал что-то более приятное. Тем не менее, я действительно считаю, что ваш тип данных должен быть чем-то вроде 'struct Vec3 {float a, b; факультативно c; }; ' – sehe

+1

@sehe Я бы предпочел не изменять тип данных из-за контекста, в котором он используется. Если я это сделаю, мне придется изменить почти половину моего конвейера. – Krienie

1

Большое предупреждение:

Код, показанный несовершенна, либо из-за ошибки, или из-за злоупотребления кармы распространения атрибутов (см комментарий).

Он вызывает неопределенное поведение (предположительно), разыменовывая итератор end() на входном векторе.

Это должно работать

floatRule = double_ | "0.0"; 

    output = -floatRule << -floatRule << -floatRule; 

Примечание, floatRule должен принять optional<float> вместо этого. Посмотреть 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); 
} 

+0

VS2012 не нравится ваше решение, к сожалению , Я получаю предупреждение о безопасности (которое я могу отключить, чтобы его можно было скомпилировать, установив -D_SCL_SECURE_NO_WARNINGS, но я бы предпочел, чтобы я не знал, какие другие ошибки я мог бы маскировать, делая это). Ошибка: 'ошибка C4996: 'std :: _ Copy_impl': вызов функции с параметрами, которые могут быть небезопасными. – Krienie

+0

Это означает, что он не мог статически проверять итераторы на функцию/не использовать проверенные (SCARY?) Итераторы. Это может быть векторные итераторы или, более вероятно, '' 0.0 "' (попробуйте с 'lit (" 0.0 ")'? Или отключите сборку DEBUG. (У меня нет MSVC) – sehe

+0

отключение сборки DEBUG делает это компиляция, но тогда выход - это лицо smilie вместо 3 поплавков (не шучу). Я, вероятно, сделал что-то еще неправильно, приспосабливая ваш пример к моему коду, но это не имеет значения. Я просто буду продолжать использовать «уродливые» Майка «code. Спасибо за ваши усилия в любом случае;) – Krienie

Смежные вопросы