【问题标题】:C++ convert json to objectC ++将json转换为对象
【发布时间】:2015-12-04 14:32:08
【问题描述】:

我正在从我的服务器下载 json。我从服务器发送的对象是 C# 对象,如下所示:

public class User
{
    public string UserName { get; set; }
    public string Info { get; set; }
}

现在,我必须在我的 C++ 应用程序中获取这些数据。我使用this library

我从服务器获得的对象类型为:web::json::value

如何从web::json::value 获取用户名?

【问题讨论】:

标签: c++ json c++11


【解决方案1】:

有两种解决方案。

手动操作

您可以提供一个接受json::value 并返回您类型的对象的函数:

User fromJson(json::value data) {
    return User{data[U("username")].as_string(), data[U("info")].as_string()};
}

自动执行

C++ 中没有反射。真的。但是如果编译器不能为你提供元数据,你可以自己提供。

让我们从创建一个属性结构开始:

template<typename Class, typename T>
struct Property {
    constexpr Property(T Class::*aMember, const char* aName) : member{aMember}, name{aName} {}

    using Type = T;

    T Class::*member;
    const char* name;
};

好的,现在我们有了编译时自省系统的构建块。

现在在您的班级用户中,添加您的元数据:

struct User {
    constexpr static auto properties = std::make_tuple(
        Property<User, std::string>{&User::username, "username"},
        Property<User, std::string>{&User::info, "info"}
    );

private:
    std::string username;
    std::string info;
};

现在您有了所需的元数据,您可以通过递归来遍历它:

template<std::size_t iteration, typename T>
void doSetData(T&& object, const json::value& data) {
    // get the property
    constexpr auto property = std::get<iteration>(std::decay_t<T>::properties);

    // get the type of the property
    using Type = typename decltype(property)::Type;

    // set the value to the member
    object.*(property.member) = asAny<Type>(data[U(property.name)]);
}

template<std::size_t iteration, typename T, typename = std::enable_if_t<(iteration > 0)>>
void setData(T&& object, const json::value& data) {
    doSetData<iteration>(object, data);
    // next iteration
    setData<iteration - 1>(object, data);
}

template<std::size_t iteration, typename T, typename = std::enable_if_t<(iteration == 0)>>
void setData(T&& object, const json::value& data) {
    doSetData<iteration>(object, data);
}

template<typename T>
T fromJson(Json::Value data) {
    T object;

    setData<std::tuple_size<decltype(T::properties)>::value - 1>(object, data);

    return object;
}

这样就可以了。

我没有测试这段代码,所以如果你有问题,请在 cmets 中告诉我。

请注意,您需要编写asAny 函数。它只是一个接受 Json::Value 并调用正确的 as_... 函数或另一个 fromJson 的函数;)

【讨论】:

  • 我正在尝试手动操作。这是我的代码:pastebin.com/aUDw2UV9 不起作用,“try/catch”返回异常“不是对象”
  • 我收到的 JSON 看起来像:[{"UserName" : "admin", "Info" : "12345"}]
  • 这看起来像是特定于这个库,也许你试图获取的密钥不存在?
  • 看,我粘贴的 JSON 是我写这行时返回的内容:“std::wcout
  • 查看库的文档,有函数 at() 而不是 [] 会引发异常。这可能有助于调试
【解决方案2】:

我重新设计了 Guillaume 解决方案以支持 c++11。下面是一个完整的工作解决方案,其中包含一些 c++14 的 decay_t 和 enable_if_t 功能的“polyfill”,可与 c++11 一起使用:

// main.cpp
#include <iostream>
#include <type_traits>
#include <tuple>
#include <jsoncpp/json/json.h>

template<typename Class, typename T>
struct Property
{
    constexpr Property(T Class::*aMember, const char *aName) :
            member{aMember}, name{aName}
    {}

    using Type = T;

    T Class::*member;
    const char *name;
};

class User
{
    std::string username;
    std::string info;
public:
    constexpr static auto properties = std::make_tuple(Property<User, std::string>{&User::username, "username"},
                                                       Property<User, std::string>{&User::info, "info"});

    const std::string &getUsername() const
    {
        return username;
    }

    void setUsername(const std::string &username)
    {
        User::username = username;
    }

    const std::string &getInfo() const
    {
        return info;
    }

    void setInfo(const std::string &info)
    {
        User::info = info;
    }
};

template< class T >
using decay_t = typename std::decay<T>::type;

template< bool B, class T = void >
using enable_if_t = typename std::enable_if<B,T>::type;

template<std::size_t iteration, typename T>
void doSetData(T &&object, const Json::Value &data)
{
    constexpr auto property = std::get<iteration>(decay_t<T>::properties);
    using Type = typename decltype(property)::Type;
    object.*(property.member) = data[property.name].asString();
}

template<std::size_t iteration, typename T, enable_if_t<(iteration > 0)>* = nullptr>
void setData(T &&object, const Json::Value &data)
{
    doSetData<iteration>(object, data);
    setData<iteration - 1>(object, data);
}

template<std::size_t iteration, typename T, enable_if_t<(iteration == 0)>* = nullptr>
void setData(T &&object, const Json::Value &data)
{
    doSetData<iteration>(object, data);
}

template<typename T>
T fromJson(Json::Value data)
{
    T object;

    setData<std::tuple_size<decltype(T::properties)>::value - 1>(object, data);

    return object;
}

int main()
{
    Json::Value value;
    value["username"] = "fiorentinoing";
    value["info"] = "https://www.linkedin.com/in/fiorentinoing/";
    User u = fromJson<User>(value);
    std::cout << "Hello, "<< u.getUsername() <<"!" << std::endl;
    std::cout << "Please, visit "<< u.getInfo() <<"." << std::endl;
    return 0;
}

以 libjsoncpp-dev 作为依赖项,为了在 Ubuntu 18.04 下构建,您可以发出:

g++ --std=c++11 -o static_reflection main.cpp -ljsoncpp

【讨论】:

    猜你喜欢
    • 2016-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多