Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/pages/conversion/forward.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,18 @@ Forward declarations of contextual conversions are done very similarly:
----
include::../../../test/doc_forward_conversion.cpp[tag=doc_forward_conversion_3,indent=0]
----


== Checking for Conversion Support

In some cases it might be necessary for you to check if a type is supported by
JSON's conversion functions. For example, you want to provide a fallback
overload for types that do not have such support. The type traits
<<ref_has_value_from>> and <<ref_has_value_to>> are intended for such checks.
They can also be forward-declared in case a physical dependency on JSON is
not desirable.

[source]
----
include::../../../test/doc_forward_conversion.cpp[tag=doc_forward_conversion_4,indent=0]
----
6 changes: 6 additions & 0 deletions include/boost/json/fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ template<class T>
typename result_for<T, value>::type
result_from_errno( int e, boost::source_location const* loc ) noexcept;

template<class T>
struct has_value_from;

template<class T>
struct has_value_to;

#endif

} // namespace json
Expand Down
14 changes: 6 additions & 8 deletions include/boost/json/value_from.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,15 @@ value_from(
If `T` can be converted to @ref value via a call to @ref value_from, the
static data member `value` is defined as `true`. Otherwise, `value` is
defined as `false`.

@see @ref value_from.
*/
#ifdef BOOST_JSON_DOCS
template<class T>
using has_value_from = __see_below__;
#else
template<class T>
using has_value_from = detail::can_convert<
detail::remove_cvref<T>, detail::value_from_conversion>;
struct has_value_from
#ifndef BOOST_JSON_DOCS
: detail::can_convert<
detail::remove_cvref<T>, detail::value_from_conversion>
{}
#endif
;

} // namespace json
} // namespace boost
Expand Down
19 changes: 8 additions & 11 deletions include/boost/json/value_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,18 @@ try_value_to(const value& jv)

/** Determine if a @ref value can be converted to `T`.

If @ref value can be converted to `T` via a
call to @ref value_to, the static data member `value`
is defined as `true`. Otherwise, `value` is
If @ref value can be converted to `T` via a call to @ref value_to, the
static data member `value` is defined as `true`. Otherwise, `value` is
defined as `false`.

@see @ref value_to
*/
#ifdef BOOST_JSON_DOCS
template<class T>
using has_value_to = __see_below__;
#else
template<class T>
using has_value_to = detail::can_convert<
detail::remove_cvref<T>, detail::value_to_conversion>;
struct has_value_to
#ifndef BOOST_JSON_DOCS
: detail::can_convert<
detail::remove_cvref<T>, detail::value_to_conversion>
{}
#endif
;

} // namespace json
} // namespace boost
Expand Down
53 changes: 53 additions & 0 deletions test/doc_forward_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ try_value_to( const value& jv );
}
// end::doc_forward_conversion_1[]

// tag::doc_forward_conversion_4[]
namespace boost {
namespace json {

template< class T >
struct has_value_from;

template< class T >
struct has_value_to;

}
}
// end::doc_forward_conversion_4[]

// tag::doc_forward_conversion_3[]
namespace boost {
namespace json {
Expand Down Expand Up @@ -156,6 +170,35 @@ tag_invoke(
}
// end::doc_forward_conversion_3[]

// tag::doc_forward_conversion_4[]

namespace third_party
{

struct json_storage
{
boost::json::value& jv;

template< class T >
friend
typename std::enable_if< boost::json::has_value_from<T>::value >::type
process(json_storage& s, T const& t)
{
boost::json::value_from(t, s.jv);
}

template< class T >
friend
typename std::enable_if< ! boost::json::has_value_from<T>::value >::type
process(json_storage& s, T const&)
{
boost::json::value_from("unknown value", s.jv);
}
};

}
// end::doc_forward_conversion_4[]

#include <boost/json/value_from.hpp>
#include <boost/json/value_to.hpp>

Expand Down Expand Up @@ -193,6 +236,16 @@ class doc_forward_conversion
BOOST_TEST( get<1>(addr2) == 115 );
BOOST_TEST( get<2>(addr2) == 81 );
BOOST_TEST( get<3>(addr2) == 22 );

jv.emplace_null();
third_party::json_storage s{jv};
process(s, addr2);
BOOST_TEST(( jv == value{ 212, 115, 81, 22 } ));

struct some_struct {};
jv.emplace_null();
process(s, some_struct{});
BOOST_TEST(( jv == value{ "unknown value" } ));
}
};

Expand Down
Loading