Non-Throwing Conversions
For the case where throwing exceptions is undesirable, Boost.JSON also provides
a non-throwing version of value_to
, the function template
try_value_to
. It returns result
, a specialised variant that
either holds a value or an error_code
.
There’s no non-throwing equivalent for value_from . This is simply
because we haven’t yet encountered a situation where value_from needed
to communicate an error to the caller.
|
The library provides non-throwing conversions for all the categories of types
it supports with value_to
. If a user wants to use it with custom types,
an overload of tag_invoke
of this form needs to be provided:
result_for<T, value>::type
tag_invoke( const try_value_to_tag< T >&, const value& );
For the class ip_address
from the section Custom Conversions this
overload may look like this:
result_for< ip_address, value >::type
tag_invoke( const try_value_to_tag< ip_address >&, value const& jv )
{
if( !jv.is_array() )
return make_error_code( std::errc::invalid_argument );
array const& arr = jv.get_array();
if( arr.size() != 4 )
return make_error_code( std::errc::invalid_argument );
boost::system::result< unsigned char > oct1
= try_value_to< unsigned char >( arr[0] );
if( !oct1 )
return make_error_code( std::errc::invalid_argument );
boost::system::result< unsigned char > oct2
= try_value_to< unsigned char >( arr[1] );
if( !oct2 )
return make_error_code( std::errc::invalid_argument );
boost::system::result< unsigned char > oct3
= try_value_to< unsigned char >( arr[2] );
if( !oct3 )
return make_error_code( std::errc::invalid_argument );
boost::system::result< unsigned char > oct4
= try_value_to< unsigned char >( arr[3] );
if( !oct4 )
return make_error_code( std::errc::invalid_argument );
return ip_address{ *oct1, *oct2, *oct3, *oct4 };
}
The overload lets us use ip_address
with try_value_to
.
value jv = parse( R"([127,0,0,12])" );
boost::system::result< ip_address > addr
= try_value_to< ip_address >( jv );
assert( addr.has_value() );
ip_address addr2{ 127, 0, 0, 12 };
assert(std::equal(
addr->begin(), addr->end(), addr2.begin() ));
// this fails without exception
addr = try_value_to< ip_address >( value() );
assert( addr.has_error() );
If try_value_to
is used with a type, for which there’s no tag_invoke
overload of the form described in this section, but there is one of the form
intended for value_to
, then the library still tries to perform the
conversion. It uses the throwing overload, and attempts to convert any thrown
exception into an error_code
. Note, though, that such approach will
likely be slower then a dedicated overload.
The opposite is also true: if there’s a tag_invoke
overload intended for
try_value_to
, but not for value_to
, then calling
value_to
will invoke the non-throwing overload, then construct
a system_error
from the error_code
and throw it. Due to these
fallbacks, it is recommended that users provide the overload from this section,
rather then the other one, if they ever intend to use try_value_to
.