| 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`.
Type satisfying `is_variant_like` | `std::variant` and similar types, e.g. `boost::variant2::variant`. | The result is equal to the result of conversion of the active variant alternative. | The result holds the first alternative for which a conversion succeeds.
Type satisfying `is_optional_like` |  | If the input value is empty, the result is a `null`. Otherwise it is equivalent to conversion of the object stored inside of optional. | The result is default constructed if the input value is `null`. Otherwise the result is constructed from the result of conversion of the input to the type stored in optional.

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`.