...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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
.
Note | |
---|---|
There's no non-throwing equivalent for |
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
will invoke the
non-throwing overload, then construct a value_to
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
.