...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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 |
|
|
---|---|---|---|
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. |
|
|
The result is equal to the input value. |
The result is equal to the input value. |
|
The result is a number equal to input and has the type
*
*
* |
The result is created via |
||
Type satisfying |
Intended for types like |
The result is a null value. |
The result is default-constructed. |
Type satisfying |
A sequence of |
The result is a |
The result is constructed from a |
Type satisfying |
A one-to-one mapping (e.g. |
The result is an |
The result is default-constructed, and elements are |
Type satisfying |
A sequence of elements, e.g. |
The result is an |
The result is default-constructed, and elements are |
Type satisfying |
A heterogenous sequence with fixed size, e.g. |
The result is an |
The result is constructed with the array elements as constructor arguments. |
Type satisfying |
The result is an |
The result is default-constructed and described members are assigned corresponding values. |
|
Type satisfying |
If the input value is equal to one of the described enumerators,
the result is a |
The result is the described enumerator, corresponding to the input
|
|
Type satisfying |
|
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 |
If the input value is empty, the result is a |
The result is default constructed if the input value is |
|
Type satisfying |
|
The result is equal to the result of |
The result is constructed from two pointers to |
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
.