| Home | Libraries | People | FAQ | More

## Value Conversion

While the `value` container makes it easy to create ad-hoc structures, often it is necessary to convert between JSON and user-defined types or types from the standard library.

The function template `value_from` provides an interface to construct a `value` from a type `T`. The function template `value_to` converts in the opposite direction, from a type `T` to `value`. Both support a wide variety of different fundamental types, such as `int` or `double`, standard library types, such as `std::string` or `std::vector<T>`, and can be extended to support user-defined types.

    std::vector< int > v1{ 1, 2, 3, 4 };

    // Convert the vector to a JSON array
    value jv = value_from( v1 );
    assert( serialize( jv ) == R"([1,2,3,4])" );

    // Convert back to vector< int >
    std::vector< int > v2 = value_to< std::vector< int > >( jv );
    assert( v1 == v2 );

For the type `T`, the appropriate conversion approach is chosen from the following list of categories. The first matching category is selected.

Table 1.3. Conversion categories

Category of T | Comment | `value_from` behavior | `value_to` behavior
--- | --- | --- | ---
Custom conversion |  | Custom behavior. | Custom behavior.
Boost.JSON container |  | The result is equal to the input value. | The result is equal to the input value.
`bool` |  | The result is equal to the input value. | The result is equal to the input value.
Arithmetic type |  | The result is a number equal to input and has the type * `std::int64_t`, if `T` is a signed integer'; or * `std::uint64_t`, if `T` is an unsigned integer; or * `double` otherwise. | The result is created via `value::to_number`.
Type satisfying `is_null_like` | Intended for types like `std::monostate`. | The result is a null value. | The result is default-constructed.
Type satisfying `is_string_like` | A sequence of `char`s, e.g. `std::string`. | The result is a `string`. | The result is constructed from a `string_view`.
Type satisfying `is_map_like` | A one-to-one mapping (e.g. `std::map`) with string-like keys. | The result is an `object`. | The result is default-constructed, and elements are `insert`-ed at the end.
Type satisfying `is_sequence_like` | A sequence of elements, e.g. `std::vector`. | The result is an `array`. | The result is default-constructed, and elements are `insert`-ed at the end.
Type satisfying `is_tuple_like` | A heterogenous sequence with fixed size, e.g. `std::tuple` and `std::pair`. | The result is an `array`. | The result is constructed with the array elements as constructor arguments.
Type satisfying `is_described_class` |  | The result is an `object` with described members' names as keys. | The result is default-constructed and described members are assigned corresponding values.
Type satisfying `is_described_enum` |  | If the input value is equal to one of the described enumerators, the result is a `string`, containing its name. Otherwise it's equal to the input value converted to its underlying type. | The result is the described enumerator, corresponding to the input `string`.

For composite types (sequences, tuples, described classes, etc.) conversion of contained objects is applied recursively. For example:

    std::map< std::string, std::pair<int, bool> > m = {
        {"a", {1, false}},
        {"b", {4, true}},
        {"c", {5, false}},
    };

    value jv = value_from( m );

    assert(( jv == object{
        {"a", array{1, false}},
        {"b", array{4, true}},
        {"c", array{5, false}},
    }));

Here, the map is converted into an `object`, since it matches `is_map_like`. Each of its keys is converted into a `string`, as `std::string` matches `is_string_like`, and each of its values is converted into an `array`, as `std::pair` matches `is_tuple_like`. Finally, elements of pairs are converted into a `std::int64_t` number and a `bool`.