mirror of
https://github.com/boostorg/describe.git
synced 2026-01-19 04:12:07 +00:00
Add three more examples
This commit is contained in:
@@ -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]
|
||||
----
|
||||
|
||||
|
||||
@@ -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<<</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’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 <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;
|
||||
}</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 <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;
|
||||
}</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 <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;
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
|
||||
@@ -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
59
example/from_json.cpp
Normal 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;
|
||||
}
|
||||
68
example/print_function.cpp
Normal file
68
example/print_function.cpp
Normal 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;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
56
example/to_json.cpp
Normal 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;
|
||||
}
|
||||
11
test/Jamfile
11
test/Jamfile
@@ -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 ;
|
||||
|
||||
Reference in New Issue
Block a user