c++ - 为什么常量字符串在用于 variant<bool, std::string> 的输入时变成 bool?

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

我已将我的问题浓缩为下面的(可能不是最小的)示例应用程序。该示例是一个通用的 JSON 解析器。 然而,它表现出两个问题。 1. 当其他选项都不通过时,当 bool_ 是变体列表中的输出器时,它总是输出 true 或 false。如果它不是最后一个,则它之后的任何内容都不会被有效使用。我不知道为什么。 2. 当输入是字符串时,永远不会从变体中触发字符串处理程序。当在变体外部使用时,它会触发。

示例代码将字符串输出简化为 karma::string,但仍然显示错误。当我把这里学到的知识返回到实际应用程序时,字符串输出将是 C 风格的转义字符串,因此仅适用于 karma::string 的东西将无济于事。

我已经阅读(并重读)Output of a boost::variant type using boost::spirit::karmaboost::spirit::karma output of string in quotation marks并且要么不能将它正确地应用于我的案例(即我毕竟不理解答案),要么它在更复杂的示例中不起作用。而且我也熟悉 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 提供了从指针类型到 bool 值的直接转换。 c++ 添加了一个 std::string 类。该类提供了来自 const char* 的构造函数。

直接转换比类构造函数更简单,因此当可以使用任何一种时,首选转换。因为它更简单,所以也不认为使用哪种转换是有歧义的。因此,虽然 char* 到字符串是预期的,但编译器确实指向 bool 值,导致输出为 bool 值。

该信息由 VeXocide 在 freenode ##spirit 聊天 channel 上提供。

因此,为了强制进行所需的转换,如果使用 std::string("STRING HERE") 而不是 "STRING HERE",它就可以工作。 boost::spirit::karma 与实际问题无关,因为这是一个 gigo 问题。

关于c++ - 为什么常量字符串在用于 variant<bool, std::string> 的输入时变成 bool?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18258315/

相关文章:

C++ 变量作用域

c++ - 从灵气中制作共享指针的 vector

c++ - 通过自定义语法使用 Boost Spirit 的流解析器

c++ - 常量重载 : Public-Private Lookup in C++ Class

c++ - bool 表达式的 spirit 解析器

c++ - 将 QKeySequence/QKeySequenceEdit 限制为只有一个快捷方式

C++ - 字节数组到值的平台独立函数,反之亦然

c++ - 定义我的二维数组以支持 [] 和 () 访问操作

c++ - 使用模板 boost 随机性

c++ - clang++、boost::spirit 和 c++11