2015-10-11 13 views
5

Sto iniziando con Boost.Hana e mi chiedevo se c'è un modo per deserializzare di nuovo in una Struct che è noto a Boost.Hana. So che è piuttosto semplice serializzare un tale Struct in una stringa json, ad esempio, ma non ho trovato alcuna informazione sull'altro senso. Al momento non è possibile deserializzare i dati con Boost.Hana o mi manca qualcosa?E 'possibile deserializzare usando Boost.Hana?

risposta

10

Hana è una libreria di metaprogrammazione. Fornisce strumenti che possono essere utilizzati per creare funzionalità più complesse come la serializzazione , ma non fornisce tale funzionalità . Semplicemente non è lo scopo di quella libreria. Inoltre, per quanto riguarda il tuo caso d'uso particolare; l'analisi non è un problema facile e altre librerie come Boost.Spirit già provano a risolverlo.

Detto questo, ho abbozzato un esempio di utilizzo di Hana per deserializzare JSON. Il risultato non è né efficiente né robusto, ma dovrebbe essere sufficiente per dare a un assaggio di come Hana potrebbe essere utilizzata per ottenere qualcosa di meglio. Risolvere il problema con correttamente questo problema richiederebbe l'implementazione di una libreria combinatore di parser alla Boost.Spirit, che non eseguirò qui. Qui si va:

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; 
} 

E poi si può utilizzare come

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); 
} 

L'esempio completo è disponibile here.

+0

Grazie, Louis. Stavo cercando di scrivere ai membri usando hana :: for_each (hana :: members (result), [] ...) senza alcun risultato. Hai creato una fantastica biblioteca! –

Problemi correlati