Современный / обобщенный c подход к макросу variadi c со строковым форматированием - PullRequest
1 голос
/ 09 февраля 2020

У меня есть библиотека (обертка вокруг nlohmann / json), которая позволяет мне десериализовать из JSON:

struct MyStruct {
    int propertyA;
    std::string propertyB;
    std::vector<int> propertyC;      
}

void from_json(const JSON::Node& json, MyStruct& s)
{
    json_get(s.propertyA, "propertyA", json);
    json_get(s.propertyB, "propertyB", json);
    json_get(s.propertyC, "propertyC", json);
}

Как вы можете видеть, в этих определениях много котельной пластины , Я использую инфраструктуру ECS, которая содержит сотни компонентов, которые я хотел бы десериализовать. Я надеюсь упростить его с помощью макроса, такого как:

struct MyStruct {
    int propertyA;
    std::string propertyB;
    std::vector<int> propertyC;    

    JSON(MyStruct, propertyA, propertyB, propertyC);
};

}

Мне известен подход oldschool __VA_ARGS__ с ручным повторением макроса N раз, но я был в надежде избежать этого с помощью более общего c / современного метода.

Возможно ли это с помощью шаблонов variadi c? Есть ли лучший способ получить что-то вроде сахара syntacti c для этого? Я использую компилятор C ++ 17.

1 Ответ

2 голосов
/ 09 февраля 2020

Очевидно, есть библиотека , которая делает именно то, что вы хотите! Вот полный пример:

#include <iostream>
#include <nlohmann/json.hpp>
#include <visit_struct/visit_struct.hpp>

struct MyStruct {
  int propertyA;
  std::string propertyB;
  std::vector<int> propertyC;
};

VISITABLE_STRUCT(MyStruct, propertyA, propertyB, propertyC);

using nlohmann::json;

template <typename T>
std::enable_if_t<visit_struct::traits::is_visitable<std::decay_t<T>>::value>
from_json(const json &j, T &obj) {
  visit_struct::for_each(obj, [&](const char *name, auto &value) {
    // json_get(value, name, j);
    j.at(name).get_to(value);
  });
}

int main() {
  json j = json::parse(R"(
    {
      "propertyA": 42,
      "propertyB": "foo",
      "propertyC": [7]
    }
  )");
  MyStruct s = j.get<MyStruct>();
  std::cout << "PropertyA: " << s.propertyA << '\n';
  std::cout << "PropertyB: " << s.propertyB << '\n';
  std::cout << "PropertyC: " << s.propertyC[0] << '\n';
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...