почему постоянная строка становится логической при использовании для ввода в variant‹bool, std::string›?

Я свел свою проблему к (возможно, не самому маленькому) примеру приложения ниже. Образец представляет собой универсальный синтаксический анализатор JSON. Тем не менее, он демонстрирует две проблемы. 1. Когда ни одна из других опций не проходит, она всегда выводит true или false, если bool_ является устройством вывода в списке вариантов. Если это не последний, все, что после него, фактически не используется. Я не могу понять, почему. 2. Когда вход представляет собой строку, обработчик строки никогда не запускается из варианта. При использовании вне варианта срабатывает.

Код примера имеет строковый вывод, упрощенный до просто karma::string, и по-прежнему показывает ошибку. Когда я возьму то, что узнал здесь, и вернусь к реальному приложению, вывод строки будет экранированной строкой в ​​​​стиле C, поэтому что-то, что работает только с karma::string, не поможет.

Я уже прочитал (и перечитал) Вывод типа boost::variant с использованием 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;
}

Отредактировано, чтобы изменить заголовок, чтобы охватить фактическую отображаемую проблему. Отредактировано, чтобы исправить промах загрузки в примере кода.


person Brian Lloyd    schedule 15.08.2013    source источник
comment
Что такое <spirit_json/karma_json_char.hpp>? Это часть какой-то сторонней библиотеки?   -  person Igor R.    schedule 15.08.2013
comment
Ваши проблемы со строками Testing... объясняются здесь .   -  person llonesmiz    schedule 15.08.2013
comment
@ИгорьР. Эти включения кажутся остатками программы до упрощения, если их удалить, она нормально компилируется (в моем случае мне также пришлось добавить #define BOOST_SPIRIT_USE_PHOENIX_V3).   -  person llonesmiz    schedule 15.08.2013


Ответы (1)


Как говорится в чьих-то комментариях, отсутствуют заголовки, на которые я пропустил удаление ссылок (они существуют здесь), но я удалил их использование.

Однако фактическая проблема, описанная выше, связана с базовыми правилами преобразования объектов C++. На случай, если кто-то еще столкнется с этим:

c обеспечивает прямое преобразование типа указателя в логическое значение. c++ добавляет класс std::string. Этот класс предоставляет конструктор из const char*.

Прямые преобразования проще, чем конструкторы классов, поэтому такое преобразование предпочтительнее, когда можно использовать любой из них. Поскольку это проще, это также не считается двусмысленным в отношении того, какое преобразование использовать. Таким образом, хотя предполагалось преобразование char* в строку, компилятор сделал указатель на логическое значение, в результате чего вывод был логическим.

Информация была предоставлена ​​VeXocide в чат-канале freenode ##spirit.

Таким образом, для принудительного преобразования, если бы std::string("STRING HERE") использовалось вместо "STRING HERE", это сработало бы. boost::spirit::karma не имело отношения к реальной проблеме, так как это была проблема с гиго.

person Brian Lloyd    schedule 15.08.2013