![]() |
Home | Libraries | People | FAQ | More |
Some users, particularly library authors, may wish to provide conversions
between their types and value, but at the same time would
prefer to avoid having their library depend on Boost.JSON. This is possible
to achieve with the help of a few forward declarations.
namespace boost { namespace json { class value; struct value_from_tag; template< class T > struct try_value_to_tag; template< class T1, class T2 > struct result_for; template< class T > void value_from( T&& t, value& jv ); template< class T > typename result_for< T, value >::type try_value_to( const value& jv ); } }
Note that value_from is declared using an
out-parameter, rather then returning its result. This overload is specifically
designed for this use-case.
After that the definitions of tag_invoke
overloads should be provided. These overloads have to be templates, since
value
is only forward-declared and hence is an incomplete type.
namespace user_ns { template< class JsonValue > void tag_invoke( const boost::json::value_from_tag&, JsonValue& jv, const ip_address& addr ) { const unsigned char* b = addr.begin(); jv = { b[0], b[1], b[2], b[3] }; } template< class JsonValue > typename boost::json::result_for< ip_address, JsonValue >::type tag_invoke( const boost::json::try_value_to_tag< ip_address >&, const JsonValue& jv ) { using namespace boost::json; if( !jv.is_array() ) return make_error_code( std::errc::invalid_argument ); auto const& arr = jv.get_array(); if( arr.size() != 4 ) return make_error_code( std::errc::invalid_argument ); auto oct1 = try_value_to< unsigned char >( arr[0] ); if( !oct1 ) return make_error_code( std::errc::invalid_argument ); auto oct2 = try_value_to< unsigned char >( arr[1] ); if( !oct2 ) return make_error_code( std::errc::invalid_argument ); auto oct3 = try_value_to< unsigned char >( arr[2] ); if( !oct3 ) return make_error_code( std::errc::invalid_argument ); auto 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 }; } }
As discussed previously, we prefer to define a non-throwing overload of
tag_invoke for try_value_to, rather then the throwing
overload for value_to, as the latter can fallback
to the former without performance degradation.