Add three more examples

This commit is contained in:
Peter Dimov
2020-09-11 21:07:29 +03:00
parent e0ae148fe3
commit 48929668f8
10 changed files with 486 additions and 7 deletions

View File

@@ -16,7 +16,7 @@ descriptors using `mp11::mp_for_each` and prints them.
[source]
----
include::../../example/printing_enums_ct.cpp[]
include::../../example/printing_enums_ct.cpp[lines=5..-1]
----
## Printing Enumerators with a Run Time Loop
@@ -27,7 +27,7 @@ an ordinary `for` loop, instead of `mp_for_each`.
[source]
----
include::../../example/printing_enums_rt.cpp[]
include::../../example/printing_enums_rt.cpp[lines=5..-1]
----
## enum_to_string
@@ -47,7 +47,7 @@ the enum value doesn't have a name.
[source]
----
include::../../example/enum_to_string.cpp[]
include::../../example/enum_to_string.cpp[lines=5..-1]
----
## string_to_enum
@@ -60,6 +60,53 @@ throws an exception.
[source]
----
include::../../example/string_to_enum.cpp[]
include::../../example/string_to_enum.cpp[lines=5..-1]
----
## Defining a Universal Print Function
This example defines a universal `operator<<` that works on
any class or struct type that has been described with
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS`.
It first prints the base classes, recursively, then prints
all the members.
(A C cast is used to access private base classes. This is
not as bad as it first appears, because we're only inspecting
the base class by printing its members, and doing so should not
change its state and hence cannot violate its invariant.)
[source]
----
include::../../example/print_function.cpp[lines=5..-1]
----
## Defining a Universal Conversion to JSON
This example defines a universal `tag_invoke` overload that
automatically converts an annotated struct to JSON by iterating
over the described public members and adding them to the return
`json::object`.
The overload is defined in namespace `app` in order to apply
to all annotated classes also defined in `app`.
The presence of private members is taken as an indication that
a universal conversion is not suitable, so the overload is
disabled in this case using `std::enable_if_t`.
[source]
----
include::../../example/to_json.cpp[lines=5..-1]
----
## Defining a Universal Conversion from JSON
Like the previous example, but in the other direction.
[source]
----
include::../../example/from_json.cpp[lines=5..-1]
----

View File

@@ -461,6 +461,9 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
<li><a href="#example_printing_enumerators_with_a_run_time_loop">Printing Enumerators with a Run Time Loop</a></li>
<li><a href="#example_enum_to_string">enum_to_string</a></li>
<li><a href="#example_string_to_enum">string_to_enum</a></li>
<li><a href="#example_defining_a_universal_print_function">Defining a Universal Print Function</a></li>
<li><a href="#example_defining_a_universal_conversion_to_json">Defining a Universal Conversion to JSON</a></li>
<li><a href="#example_defining_a_universal_conversion_from_json">Defining a Universal Conversion from JSON</a></li>
</ul>
</li>
<li><a href="#reference">Reference</a>
@@ -932,6 +935,231 @@ int main()
</div>
</div>
</div>
<div class="sect2">
<h3 id="example_defining_a_universal_print_function">Defining a Universal Print Function</h3>
<div class="paragraph">
<p>This example defines a universal <code>operator&lt;&lt;</code> that works on
any class or struct type that has been described with
<code>BOOST_DESCRIBE_STRUCT</code> or <code>BOOST_DESCRIBE_CLASS</code>.</p>
</div>
<div class="paragraph">
<p>It first prints the base classes, recursively, then prints
all the members.</p>
</div>
<div class="paragraph">
<p>(A C cast is used to access private base classes. This is
not as bad as it first appears, because we&#8217;re only inspecting
the base class by printing its members, and doing so should not
change its state and hence cannot violate its invariant.)</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#include &lt;boost/describe.hpp&gt;
#include &lt;boost/mp11.hpp&gt;
#include &lt;ostream&gt;
using namespace boost::describe;
template&lt;class T,
class Bd = describe_base_classes&lt;T, mod_any_access&gt;,
class Md = describe_data_members&lt;T, mod_any_access&gt;&gt;
std::ostream&amp; operator&lt;&lt;( std::ostream &amp; os, T const &amp; t )
{
os &lt;&lt; "{";
bool first = true;
boost::mp11::mp_for_each&lt; Bd &gt;([&amp;](auto D){
if( !first ) { os &lt;&lt; ", "; } first = false;
using B = typename decltype(D)::type;
os &lt;&lt; (B const&amp;)t;
});
boost::mp11::mp_for_each&lt; Md &gt;([&amp;](auto D){
if( !first ) { os &lt;&lt; ", "; } first = false;
os &lt;&lt; "." &lt;&lt; D.name &lt;&lt; " = " &lt;&lt; t.*D.pointer;
});
os &lt;&lt; "}";
return os;
}
struct X
{
int m1 = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (m1), ())
struct Y
{
int m2 = 2;
};
BOOST_DESCRIBE_STRUCT(Y, (), (m2), ())
class Z: public X, private Y
{
int m1 = 3;
int m2 = 4;
BOOST_DESCRIBE_CLASS(Z, (X, Y), (), (m1, m2), ())
};
#include &lt;iostream&gt;
int main()
{
std::cout &lt;&lt; Z() &lt;&lt; std::endl;
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="example_defining_a_universal_conversion_to_json">Defining a Universal Conversion to JSON</h3>
<div class="paragraph">
<p>This example defines a universal <code>tag_invoke</code> overload that
automatically converts an annotated struct to JSON by iterating
over the described public members and adding them to the return
<code>json::object</code>.</p>
</div>
<div class="paragraph">
<p>The overload is defined in namespace <code>app</code> in order to apply
to all annotated classes also defined in <code>app</code>.</p>
</div>
<div class="paragraph">
<p>The presence of private members is taken as an indication that
a universal conversion is not suitable, so the overload is
disabled in this case using <code>std::enable_if_t</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#include &lt;boost/describe.hpp&gt;
#include &lt;boost/mp11.hpp&gt;
#include &lt;boost/json.hpp&gt;
#include &lt;type_traits&gt;
#include &lt;vector&gt;
#include &lt;map&gt;
namespace app
{
template&lt;class T,
class D1 = boost::describe::describe_data_members&lt;T, boost::describe::mod_public&gt;,
class D2 = boost::describe::describe_data_members&lt;T, boost::describe::mod_private&gt;,
class En = std::enable_if_t&lt;boost::mp11::mp_empty&lt;D2&gt;::value&gt; &gt;
void tag_invoke( boost::json::value_from_tag const&amp;, boost::json::value&amp; v, T const &amp; t )
{
auto&amp; obj = v.emplace_object();
boost::mp11::mp_for_each&lt;D1&gt;([&amp;](auto D){
obj[ D.name ] = boost::json::value_from( t.*D.pointer );
});
}
struct A
{
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y), ())
struct B
{
std::vector&lt;A&gt; v;
std::map&lt;std::string, A&gt; m;
};
BOOST_DESCRIBE_STRUCT(B, (), (v, m), ())
} // namespace app
#include &lt;iostream&gt;
int main()
{
app::B b{ { { 1, 2 }, { 3, 4 } }, { { "k1", { 5, 6 } }, { "k2", { 7, 8 } } } };
std::cout &lt;&lt; boost::json::value_from( b ) &lt;&lt; std::endl;
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="example_defining_a_universal_conversion_from_json">Defining a Universal Conversion from JSON</h3>
<div class="paragraph">
<p>Like the previous example, but in the other direction.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#include &lt;boost/describe.hpp&gt;
#include &lt;boost/mp11.hpp&gt;
#include &lt;boost/json.hpp&gt;
#include &lt;type_traits&gt;
namespace app
{
template&lt;class T&gt; void extract( boost::json::object const &amp; obj, char const * name, T &amp; value )
{
value = boost::json::value_to&lt;T&gt;( obj.at( name ) );
}
template&lt;class T,
class D1 = boost::describe::describe_data_members&lt;T, boost::describe::mod_public&gt;,
class D2 = boost::describe::describe_data_members&lt;T, boost::describe::mod_private&gt;,
class En = std::enable_if_t&lt;boost::mp11::mp_empty&lt;D2&gt;::value&gt; &gt;
T tag_invoke( boost::json::value_to_tag&lt;T&gt; const&amp;, boost::json::value const&amp; v )
{
auto const&amp; obj = v.as_object();
T t = {};
boost::mp11::mp_for_each&lt;D1&gt;([&amp;](auto D){
extract( obj, D.name, t.*D.pointer );
});
return t;
}
struct A
{
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y), ())
} // namespace app
#include &lt;iostream&gt;
int main()
{
boost::json::value jv{ { "x", 1 }, { "y", 2 } };
std::cout &lt;&lt; "jv: " &lt;&lt; jv &lt;&lt; std::endl;
auto a = boost::json::value_to&lt;app::A&gt;( jv );
std::cout &lt;&lt; "a: { " &lt;&lt; a.x &lt;&lt; ", " &lt;&lt; a.y &lt;&lt; " }" &lt;&lt; std::endl;
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">

View File

@@ -1,3 +1,7 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>

59
example/from_json.cpp Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <type_traits>
namespace app
{
template<class T> void extract( boost::json::object const & obj, char const * name, T & value )
{
value = boost::json::value_to<T>( obj.at( name ) );
}
template<class T,
class D1 = boost::describe::describe_data_members<T, boost::describe::mod_public>,
class D2 = boost::describe::describe_data_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
T tag_invoke( boost::json::value_to_tag<T> const&, boost::json::value const& v )
{
auto const& obj = v.as_object();
T t = {};
boost::mp11::mp_for_each<D1>([&](auto D){
extract( obj, D.name, t.*D.pointer );
});
return t;
}
struct A
{
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y), ())
} // namespace app
#include <iostream>
int main()
{
boost::json::value jv{ { "x", 1 }, { "y", 2 } };
std::cout << "jv: " << jv << std::endl;
auto a = boost::json::value_to<app::A>( jv );
std::cout << "a: { " << a.x << ", " << a.y << " }" << std::endl;
}

View File

@@ -0,0 +1,68 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <ostream>
using namespace boost::describe;
template<class T,
class Bd = describe_base_classes<T, mod_any_access>,
class Md = describe_data_members<T, mod_any_access>>
std::ostream& operator<<( std::ostream & os, T const & t )
{
os << "{";
bool first = true;
boost::mp11::mp_for_each< Bd >([&](auto D){
if( !first ) { os << ", "; } first = false;
using B = typename decltype(D)::type;
os << (B const&)t;
});
boost::mp11::mp_for_each< Md >([&](auto D){
if( !first ) { os << ", "; } first = false;
os << "." << D.name << " = " << t.*D.pointer;
});
os << "}";
return os;
}
struct X
{
int m1 = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (m1), ())
struct Y
{
int m2 = 2;
};
BOOST_DESCRIBE_STRUCT(Y, (), (m2), ())
class Z: public X, private Y
{
int m1 = 3;
int m2 = 4;
BOOST_DESCRIBE_CLASS(Z, (X, Y), (), (m1, m2), ())
};
#include <iostream>
int main()
{
std::cout << Z() << std::endl;
}

View File

@@ -1,3 +1,7 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <cstdio>

View File

@@ -1,3 +1,7 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <cstdio>
#include <array>

View File

@@ -1,3 +1,7 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <stdexcept>

56
example/to_json.cpp Normal file
View File

@@ -0,0 +1,56 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <type_traits>
#include <vector>
#include <map>
namespace app
{
template<class T,
class D1 = boost::describe::describe_data_members<T, boost::describe::mod_public>,
class D2 = boost::describe::describe_data_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
void tag_invoke( boost::json::value_from_tag const&, boost::json::value& v, T const & t )
{
auto& obj = v.emplace_object();
boost::mp11::mp_for_each<D1>([&](auto D){
obj[ D.name ] = boost::json::value_from( t.*D.pointer );
});
}
struct A
{
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y), ())
struct B
{
std::vector<A> v;
std::map<std::string, A> m;
};
BOOST_DESCRIBE_STRUCT(B, (), (v, m), ())
} // namespace app
#include <iostream>
int main()
{
app::B b{ { { 1, 2 }, { 3, 4 } }, { { "k1", { 5, 6 } }, { "k2", { 7, 8 } } } };
std::cout << boost::json::value_from( b ) << std::endl;
}

View File

@@ -20,7 +20,12 @@ run data_members_test.cpp ;
run data_members_test2.cpp ;
run member_functions_test.cpp ;
run ../example/printing_enums_ct.cpp : : : <toolset>msvc:<cxxflags>"-wd4100" ;
local NW = <toolset>msvc-14.0:<cxxflags>"-wd4100" ;
run ../example/printing_enums_ct.cpp : : : $(NW) ;
run ../example/printing_enums_rt.cpp ;
run ../example/enum_to_string.cpp : : : <toolset>msvc:<cxxflags>"-wd4100" ;
run ../example/string_to_enum.cpp : : : <toolset>msvc:<cxxflags>"-wd4100" ;
run ../example/enum_to_string.cpp : : : $(NW) ;
run ../example/string_to_enum.cpp : : : $(NW) ;
run ../example/print_function.cpp : : : $(NW) ;
run ../example/to_json.cpp /boost//json /boost//container : : : $(NW) ;
run ../example/from_json.cpp /boost//json : : : <toolset>msvc-14.0:<build>no ;