Генерация значения по умолчанию, когда ничего не найдено

У меня есть входной вектор, который может иметь любой размер между пустым и 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" (последнее значение должно быть значением по умолчанию).

3

Решение

Не красиво, но работает

#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;
}
2

Другие решения

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

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

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

    floatRule = double_ | "0.0";

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

Заметка, floatRule должен принять optional<float> вместо. Видеть это Жить на Колиру

Минимальный пример:

#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);
}

1