我从我的服务器下载json.我从服务器发送的对象是C#对象,如下所示:
public class User
{
public string UserName { get; set; }
public string Info { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,我必须在我的C++应用程序中获取此数据.我使用这个库.
我从服务器获得的对象是这样的类型: web::json::value
如何从中获取UserName web::json::value?
有两种解决方案.
你可以提供一个函数来获取json::value并返回你的类型的对象:
User fromJson(json::value data) {
return User{data[U("username")].as_string(), data[U("info")].as_string()};
}
Run Code Online (Sandbox Code Playgroud)
没有反思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;
};
Run Code Online (Sandbox Code Playgroud)
好的,现在我们有了编译时内省系统的构建块.
现在在您的班级用户中,添加您的元数据:
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;
};
Run Code Online (Sandbox Code Playgroud)
现在您已拥有所需的元数据,您可以通过递归迭代它:
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;
}
Run Code Online (Sandbox Code Playgroud)
那就行了.
我没有测试这段代码,所以如果你遇到麻烦,请在评论中告诉我.
请注意,您需要编写该asAny函数.它只是一个函数,它接受一个Json :: Value并调用正确的as_...函数,或另一个fromJson;)
我重新设计了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;
}
Run Code Online (Sandbox Code Playgroud)
使用 libjsoncpp-dev 作为依赖项,为了在 Ubuntu 18.04 下构建,您可以发出:
g++ --std=c++11 -o static_reflection main.cpp -ljsoncpp
Run Code Online (Sandbox Code Playgroud)