Я сократил мою проблему до (возможно, не самого маленького) примера приложения ниже. Примером является общий анализатор JSON.
Тем не менее, он имеет две проблемы.
1. Когда ни один из других параметров не проходит, он всегда выводит истину или ложь, когда bool_ является выходным параметром в списке вариантов. Если это не последний, что-нибудь после этого эффективно не используется. Я не могу понять, почему.
2. Когда вход является строкой, обработчик строки никогда не запускается из варианта. При использовании вне варианта он срабатывает.
Код примера имеет вывод строки, упрощенный до karma :: string, и все равно выдает ошибку. Когда я возьму то, что здесь изучено, и вернусь к реальному приложению, вывод строки будет экранированной строкой в стиле C, поэтому что-то, что работает только с karma :: string, не поможет.
Я уже прочитал (и перечитал) Вывод Boost :: варианта типа с использованием Boost :: Spirit :: Karma а также boost :: spirit :: karma вывод строки в кавычках и либо не может правильно применить его в моем случае (то есть я не понимаю ответ в конце концов), либо он не работает в более сложном примере. И я также знаком с примером кода mini_xml.
Любые предложения о том, что я делаю не так? И почему то, что я делаю, неправильно, а исправление верно?
Вся помощь очень ценится.
#include <boost/variant/recursive_variant.hpp>
#include <string>
#include <vector>
namespace lloyd
{
namespace json
{
struct null
{
bool operator==(const null& cmp) {return true; }
};
struct element;
typedef boost::make_recursive_variant<null, bool, long, double, std::string, std::vector<element>, std::vector<boost::recursive_variant_> >::type value;
struct element
{
std::string name;
json::value value;
inline element(const element& src): name(src.name), value(src.value) {}
inline element(const std::string& name, const json::value& value): name(name), value(value) {}
inline element() {}
};
typedef std::vector<element> object;
}
}
#include <boost/fusion/adapted.hpp>
BOOST_FUSION_ADAPT_STRUCT(
lloyd::json::element,
(std::string, name)
(lloyd::json::value, value)
)
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/karma_auto.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace lloyd { namespace json { namespace karma {
template <typename OutputIterator>
struct json_object_out_generator
: boost::spirit::karma::grammar<OutputIterator, json::object(bool, unsigned, unsigned) >
{
// JSON Output Grammars
boost::spirit::karma::rule<OutputIterator, std::vector<json::value>(bool, unsigned, unsigned) > array_rule;
boost::spirit::karma::rule<OutputIterator, json::null(bool, unsigned, unsigned) > null_rule;
boost::spirit::karma::rule<OutputIterator, json::value(bool, unsigned, unsigned) > value_rule;
boost::spirit::karma::rule<OutputIterator, json::element(bool, unsigned, unsigned) > elem_rule;
boost::spirit::karma::rule<OutputIterator, json::object(bool, unsigned, unsigned) > obj_rule;
json_object_out_generator() : json_object_out_generator::base_type(obj_rule)
{
using boost::spirit::lit;
using boost::spirit::_r1;
using boost::spirit::_r2;
using boost::spirit::_r3;
namespace karma=boost::spirit::karma;
null_rule %= karma::eps << boost::spirit::karma::lit("null");
array_rule %= lit("[") << -(value_rule(_r1, _r2, _r3) % lit(",") ) << "]";
value_rule %= ( null_rule(_r1, _r2, _r3) | karma::string | karma::long_ | karma::double_ | obj_rule(_r1, _r2, _r3) | array_rule(_r1, _r2, _r3) | karma::bool_);
elem_rule %= boost::spirit::karma::string << ":" << -value_rule(_r1, _r2+1, _r3);
obj_rule %= boost::spirit::lit("{")
<< -boost::spirit::buffer[( elem_rule(_r1, _r2+1, _r3) % ',' ) ]
<< "}";
}
};
}}}
#include <vector>
#include <sstream>
#include <iomanip>
#include <boost/assign/list_of.hpp>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
int main(int argc, const char* argv[])
{
using lloyd::json::value;
using lloyd::json::element;
using lloyd::json::null;
lloyd::json::object obj;
lloyd::json::object sobj;
std::vector<value> t5;
t5 += null(), true, false, value("Testing"), sobj;
obj += element("T1", null()), element("T2", true), element("T3", false);
obj += element("T4", "Testing 4"), element("T5", t5), element("T6", sobj);
obj += element("NT0", (long)50), element("NT1", 50.5), element("NT2", 50.0);
std::stringstream s;
typedef boost::spirit::karma::ostream_iterator<char> out_itr;
out_itr so(s);
lloyd::json::karma::json_object_out_generator<out_itr> json_object_out; // Our grammar definition
boost::spirit::karma::generate(so, json_object_out(true, 0, 1), obj);
std::cout << "Result:\n";
std::cout << s.str() << std::endl;
return 0;
}
Отредактировано, чтобы изменить заголовок, чтобы покрыть фактическую отображаемую проблему.
Отредактировано, чтобы исправить ошибку при загрузке примера кода.
Как говорится в чьих-то комментариях, отсутствующими являются заголовки, на которые я пропустил удаление ссылок (они существуют здесь), но я удалил использование.
Однако актуальная проблема, описанная выше, связана с базовыми правилами преобразования объектов C ++. В случае, если кто-то еще сталкивается с этим:
c обеспечивает прямое преобразование из типа указателя в логическое значение.
C ++ добавляет класс std :: string. Этот класс предоставляет конструктор из const char *.
Прямые преобразования проще, чем конструкторы классов, поэтому такое преобразование предпочтительнее, когда можно использовать любой из них. Поскольку это проще, это также не считается двусмысленным в отношении того, какое преобразование использовать. Таким образом, хотя char * to string — это то, что было задумано, компилятор сделал указатель на логическое значение, в результате чего вывод был логическим.
Информация была предоставлена VeXocide на канале чата freenode ## spirit.
Таким образом, чтобы вызвать желаемое преобразование, если бы вместо «STRING HERE» использовался std :: string («STRING HERE»), он бы работал. boost :: spirit :: karma не имел никакого отношения к актуальной проблеме, так как это была проблема гиго.
Других решений пока нет …