是否可以使用Boost.Hana反序列化?

Xar*_*ska 6 c++ c++14 boost-hana

我开始使用Boost.Hana,并想知道是否有一种方法可以反序列化为Boost.Hana已知的Struct.我知道将这样的struct序列化为json字符串非常简单,但是我没有找到任何关于反过来的信息.目前是不是可以用Boost.Hana反序列化数据或者我错过了什么?

Lou*_*nne 12

Hana是一个元编程库.它提供的工具可用于构建更复杂的功能,如序列化,但它本身不提供此类功能.它根本不是该库的范围.另外,关于您的特定用例; 解析不是一个容易的问题,像Boost.Spirit这样的其他库已经尝试解决它.

话虽这么说,我勾勒出一个使用Hana反序列化JSON的例子.结果既不高效也不健壮,但它应该足以让你一瞥Hana如何用来实现更好的目标.正确解决这个问题需要实现一个解析器组合库à-la Boost.Spirit,我不会在这里做.干得好:

template <typename T>
  std::enable_if_t<std::is_same<T, int>::value,
T> from_json(std::istream& in) {
    T result;
    in >> result;
    return result;
}

template <typename T>
  std::enable_if_t<std::is_same<T, std::string>::value,
T> from_json(std::istream& in) {
    char quote;
    in >> quote;

    T result;
    char c;
    while (in.get(c) && c != '"') {
        result += c;
    }
    return result;
}


template <typename T>
  std::enable_if_t<hana::Struct<T>::value,
T> from_json(std::istream& in) {
    T result;
    char brace;
    in >> brace;

    hana::for_each(hana::keys(result), [&](auto key) {
        in.ignore(std::numeric_limits<std::streamsize>::max(), ':');
        auto& member = hana::at_key(result, key);
        using Member = std::remove_reference_t<decltype(member)>;
        member = from_json<Member>(in);
    });
    in >> brace;
    return result;
}

template <typename Xs>
  std::enable_if_t<hana::Sequence<Xs>::value,
Xs> from_json(std::istream& in) {
    Xs result;
    char bracket;
    in >> bracket;
    hana::length(result).times.with_index([&](auto i) {
        if (i != 0u) {
            char comma;
            in >> comma;
        }

        auto& element = hana::at(result, i);
        using Element = std::remove_reference_t<decltype(element)>;
        element = from_json<Element>(in);
    });
    in >> bracket;
    return result;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像使用它一样

struct Car {
    BOOST_HANA_DEFINE_STRUCT(Car,
        (std::string, brand),
        (std::string, model)
    );
};

struct Person {
    BOOST_HANA_DEFINE_STRUCT(Person,
        (std::string, name),
        (std::string, last_name),
        (int, age)
    );
};

int main() {
    std::istringstream json(R"EOS(
        [
            {
                "name": "John",
                "last_name": "Doe",
                "age": 30
            },
            {
                "brand": "BMW",
                "model": "Z3"
            },
            {
                "brand": "Audi",
                "model": "A4"
            }
        ]
    )EOS");

    auto actual = from_json<hana::tuple<Person, Car, Car>>(json);

    auto expected = hana::make_tuple(Person{"John", "Doe", 30},
                                     Car{"BMW", "Z3"},
                                     Car{"Audi", "A4"});

    assert(actual == expected);
}
Run Code Online (Sandbox Code Playgroud)

完整的示例可在此处获得.