mirror of
https://github.com/boostorg/describe.git
synced 2026-01-23 05:22:18 +00:00
Compare commits
16 Commits
feature/ne
...
boost-1.77
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e6f861f89 | ||
|
|
4a4dd302cb | ||
|
|
be5bf613e6 | ||
|
|
57e62f34b8 | ||
|
|
7e9f1f0eb9 | ||
|
|
0b65ca3229 | ||
|
|
f66002254b | ||
|
|
abbc5bec0c | ||
|
|
ef93d95e71 | ||
|
|
c48ef40b1d | ||
|
|
78c861d0bc | ||
|
|
23cc0011ad | ||
|
|
245c2de80a | ||
|
|
22eaa99867 | ||
|
|
53d7313731 | ||
|
|
65066cd2d0 |
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@@ -38,15 +38,20 @@ jobs:
|
||||
- toolset: gcc-8
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
install: g++-8
|
||||
- toolset: gcc-9
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-10
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-11
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
install: g++-11
|
||||
- toolset: clang
|
||||
compiler: clang++-3.5
|
||||
cxxstd: "03,11,14"
|
||||
cxxstd: "03,11"
|
||||
os: ubuntu-16.04
|
||||
install: clang-3.5
|
||||
- toolset: clang
|
||||
@@ -83,6 +88,7 @@ jobs:
|
||||
compiler: clang++-6.0
|
||||
cxxstd: "03,11,14,17"
|
||||
os: ubuntu-18.04
|
||||
install: clang-6.0
|
||||
- toolset: clang
|
||||
compiler: clang++-7
|
||||
cxxstd: "03,11,14,17"
|
||||
@@ -92,14 +98,24 @@ jobs:
|
||||
compiler: clang++-8
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: clang-8
|
||||
- toolset: clang
|
||||
compiler: clang++-9
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: clang-9
|
||||
- toolset: clang
|
||||
compiler: clang++-10
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
- toolset: clang
|
||||
compiler: clang++-11
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
- toolset: clang
|
||||
compiler: clang++-12
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: macos-10.15
|
||||
|
||||
25
CMakeLists.txt
Normal file
25
CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by `boostdep --cmake describe`
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_describe VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_describe INTERFACE)
|
||||
add_library(Boost::describe ALIAS boost_describe)
|
||||
|
||||
target_include_directories(boost_describe INTERFACE include)
|
||||
|
||||
target_link_libraries(boost_describe
|
||||
INTERFACE
|
||||
Boost::mp11
|
||||
)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
A C++14 reflection library. Provides macros for describing enumerators and
|
||||
struct/class members, and primitives for querying this information. See
|
||||
[the documentation](https://pdimov.github.io/describe) for more information
|
||||
and usage examples.
|
||||
[the documentation](https://www.boost.org/doc/libs/develop/libs/describe/)
|
||||
for more information and usage examples.
|
||||
|
||||
## Supported Compilers
|
||||
|
||||
@@ -16,4 +16,5 @@ Tested on [Travis](https://travis-ci.org/github/pdimov/describe/) and
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
Distributed under the
|
||||
[Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
|
||||
1
doc/.gitignore
vendored
1
doc/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/pdf/
|
||||
/html/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
////
|
||||
Copyright 2020 Peter Dimov
|
||||
Copyright 2020, 2021 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
@@ -70,6 +70,8 @@ private:
|
||||
|
||||
It takes three member lists, for the public, protected, and private members.
|
||||
|
||||
## Retrieving Class Properties
|
||||
|
||||
Once a type `T` is annotated, its properties can be retrieved via
|
||||
`describe_bases<T, M>` and `describe_members<T, M>` (`M` is a bitmask of
|
||||
modifiers such as `mod_public | mod_static | mod_function`).
|
||||
@@ -84,7 +86,7 @@ excludes them. The other two modifiers work similarly.
|
||||
|
||||
`describe_members` takes a bitwise-or combination of the following possible
|
||||
modifiers: `mod_public`, `mod_protected`, `mod_private`, `mod_static`,
|
||||
`mod_function`, `mod_inherited`, `mod_hidden`.
|
||||
`mod_function`, `mod_any_member`, `mod_inherited`, `mod_hidden`.
|
||||
|
||||
The access modifiers work the same as with `describe_bases`.
|
||||
|
||||
@@ -97,6 +99,9 @@ the nonstatic members are returned.
|
||||
When `mod_function` is present, the member functions are returned, otherwise
|
||||
the data members are returned.
|
||||
|
||||
When `mod_any_member` is present, `mod_static` and `mod_function` are ignored
|
||||
and all members are returned regardless of kind.
|
||||
|
||||
When `mod_inherited` is present, members of base classes are also returned.
|
||||
|
||||
When `mod_hidden` is present, hidden inherited members are included. A member
|
||||
|
||||
@@ -47,6 +47,28 @@ For defining `enum class E2` instead, use `BOOST_DEFINE_ENUM_CLASS`. To add
|
||||
an underlying type, i.e. `enum E3: int` or `enum class E4: unsigned char`,
|
||||
use `BOOST_DEFINE_FIXED_ENUM` and `BOOST_DEFINE_FIXED_ENUM_CLASS`, respectively.
|
||||
|
||||
If your enumeration type is nested inside a class or a `struct`, use the
|
||||
`BOOST_DESCRIBE_NESTED_ENUM` macro next to the `enum`, as follows:
|
||||
|
||||
```
|
||||
class X
|
||||
{
|
||||
private:
|
||||
|
||||
enum class E
|
||||
{
|
||||
v1,
|
||||
v2
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_NESTED_ENUM(E, v1, v2)
|
||||
|
||||
public:
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Once an enumeration type `E` is annotated, one can use `describe_enumerators<E>`
|
||||
to obtain a _descriptor list_. (`describe_enumerators` is defined in the
|
||||
`boost::describe` namespace, in `<boost/describe/enumerators.hpp>`.)
|
||||
|
||||
@@ -86,12 +86,43 @@ change its state and hence cannot violate its invariant.)
|
||||
include::../../example/print_function.cpp[lines=5..-1]
|
||||
----
|
||||
|
||||
[#example_hash_value]
|
||||
## Implementing hash_value
|
||||
|
||||
This example defines a universal `hash_value` overload that
|
||||
computes the hash value of an annotated struct or class. It
|
||||
does so by iterating over the described bases and members and
|
||||
calling `boost::hash_combine` on each.
|
||||
|
||||
The overload is defined in namespace `app` in order to apply
|
||||
to all annotated classes also defined in `app`.
|
||||
|
||||
[source]
|
||||
----
|
||||
include::../../example/hash_value.cpp[lines=5..-1]
|
||||
----
|
||||
|
||||
[#example_equality]
|
||||
## Implementing operator==
|
||||
|
||||
This example defines a universal `operator==` overload that
|
||||
iterates over the described bases and members and compares
|
||||
them for equality using `==`.
|
||||
|
||||
The overload is defined in namespace `app` in order to apply
|
||||
to all annotated classes also defined in `app`.
|
||||
|
||||
[source]
|
||||
----
|
||||
include::../../example/equality.cpp[lines=5..-1]
|
||||
----
|
||||
|
||||
[#example_to_json]
|
||||
## Automatic Conversion to JSON
|
||||
|
||||
This example defines a universal `tag_invoke` overload that
|
||||
automatically converts an annotated struct to a
|
||||
http://master.json.cpp.al[Boost.JSON] value by iterating
|
||||
http://boost.org/libs/json[Boost.JSON] value by iterating
|
||||
over the described public members and adding them to the return
|
||||
`boost::json::object`.
|
||||
|
||||
@@ -136,7 +167,7 @@ include::../../example/serialization.cpp[lines=5..-1]
|
||||
|
||||
This example defines a generic `call` function that can be used to
|
||||
invoke a member function by name, with the arguments passed in a
|
||||
http://master.json.cpp.al[Boost.JSON] array. The result is returned
|
||||
http://boost.org/libs/json[Boost.JSON] array. The result is returned
|
||||
in a `boost::json::value`.
|
||||
|
||||
[source]
|
||||
@@ -144,3 +175,14 @@ in a `boost::json::value`.
|
||||
include::../../example/json_rpc.cpp[lines=5..-1]
|
||||
----
|
||||
|
||||
[#example_console]
|
||||
## Interactive Variable Console
|
||||
|
||||
This example implements an interactive console that allows printing
|
||||
and modifying variables. It uses http://boost.org/libs/json[Boost.JSON]
|
||||
for converting the variables to and from a string form.
|
||||
|
||||
[source]
|
||||
----
|
||||
include::../../example/console.cpp[lines=9..-1]
|
||||
----
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
////
|
||||
Copyright 2020 Peter Dimov
|
||||
Copyright 2020, 2021 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
@@ -12,7 +12,8 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
```
|
||||
#define BOOST_DESCRIBE_ENUM(E, ...) /*...*/
|
||||
#define BOOST_DESCRIBE_ENUM_CLASS(E, ...) /*...*/
|
||||
|
||||
#define BOOST_DESCRIBE_NESTED_ENUM(E, ...) /*...*/
|
||||
|
||||
#define BOOST_DEFINE_ENUM(E, ...) \
|
||||
enum E { __VA_ARGS__ }; BOOST_DESCRIBE_ENUM(E, __VA_ARGS__)
|
||||
@@ -48,6 +49,13 @@ struct Di
|
||||
```
|
||||
where `vi` is the corresponding identifier passed to the macro.
|
||||
|
||||
### BOOST_DESCRIBE_NESTED_ENUM
|
||||
|
||||
`BOOST_DESCRIBE_NESTED_ENUM(E, v1, v2, ..., vN)` is similar to
|
||||
`BOOST_DESCRIBE_ENUM` and is used to annotate enumeration types nested inside
|
||||
class (or `struct`) types. It should be placed in the class type where the
|
||||
`enum` is defined.
|
||||
|
||||
### BOOST_DEFINE_ENUM
|
||||
|
||||
`BOOST_DEFINE_ENUM(E, v1, v2, ..., vN)` is a convenience macro expanding to
|
||||
@@ -190,8 +198,9 @@ enum modifiers
|
||||
mod_virtual = 8,
|
||||
mod_static = 16,
|
||||
mod_function = 32,
|
||||
mod_inherited = 64,
|
||||
mod_hidden = 128,
|
||||
mod_any_member = 64,
|
||||
mod_inherited = 128,
|
||||
mod_hidden = 256,
|
||||
};
|
||||
|
||||
constexpr modifiers mod_any_access = static_cast<modifiers>( mod_public | mod_protected | mod_private );
|
||||
@@ -211,6 +220,7 @@ following flags:
|
||||
* `mod_virtual` - returned when a base class is a virtual base
|
||||
* `mod_static` - returns static members (when not given, returns nonstatic members)
|
||||
* `mod_function` - returns member functions (when not given, returns data members)
|
||||
* `mod_any_member` - overrides `mod_static` and `mod_function` and returns all members regardless of kind
|
||||
* `mod_inherited` - includes members of base classes
|
||||
* `mod_hidden` - includes hidden inherited members
|
||||
|
||||
@@ -261,8 +271,8 @@ template<class T, unsigned M> using describe_members = /*...*/;
|
||||
### describe_members<T, M>
|
||||
|
||||
`M` must be a bitwise-or combination of `mod_public`, `mod_protected`,
|
||||
`mod_private`, `mod_static`, `mod_function`, `mod_inherited`, and
|
||||
`mod_hidden`, and acts as a filter.
|
||||
`mod_private`, `mod_static`, `mod_function`, `mod_any_member`,
|
||||
`mod_inherited`, and `mod_hidden`, and acts as a filter.
|
||||
|
||||
`describe_members<T, M>` returns `L<D1, D2, ..., Dn>`, where `L` is a class
|
||||
template of the form
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
129
example/console.cpp
Normal file
129
example/console.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2021 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable: 4702) // unreachable code
|
||||
#endif
|
||||
|
||||
#include <boost/describe.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
// get variable
|
||||
|
||||
template<class Scope> boost::json::value get( Scope& scope, boost::string_view name )
|
||||
{
|
||||
using Md = boost::describe::describe_members<Scope, boost::describe::mod_public>;
|
||||
|
||||
bool found = false;
|
||||
boost::json::value result;
|
||||
|
||||
boost::mp11::mp_for_each<Md>([&](auto D) {
|
||||
|
||||
if( !found && name == D.name )
|
||||
{
|
||||
result = boost::json::value_from( scope.*D.pointer );
|
||||
found = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if( !found )
|
||||
{
|
||||
throw std::invalid_argument(
|
||||
std::string( "'" ) + std::string( name ) + "': no such variable" );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// set variable
|
||||
|
||||
template<class T> void set_impl( T & t, boost::string_view /*name*/, boost::json::value const& value )
|
||||
{
|
||||
t = boost::json::value_to<T>( value );
|
||||
}
|
||||
|
||||
template<class T> void set_impl( T const & /*t*/, boost::string_view name, boost::json::value const& /*value*/ )
|
||||
{
|
||||
throw std::invalid_argument(
|
||||
std::string( "'" ) + std::string( name ) + "': variable cannot be modified" );
|
||||
}
|
||||
|
||||
template<class Scope> void set( Scope& scope, boost::string_view name, boost::json::value const& value )
|
||||
{
|
||||
using Md = boost::describe::describe_members<Scope, boost::describe::mod_public>;
|
||||
|
||||
bool found = false;
|
||||
|
||||
boost::mp11::mp_for_each<Md>([&](auto D) {
|
||||
|
||||
if( !found && name == D.name )
|
||||
{
|
||||
set_impl( scope.*D.pointer, name, value );
|
||||
found = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if( !found )
|
||||
{
|
||||
throw std::invalid_argument(
|
||||
std::string( "'" ) + std::string( name ) + "': no such variable" );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
struct globals
|
||||
{
|
||||
std::string const help = "Enter a variable name ('x', 'y', 'v', or 'm') to print its value; enter variable=value to assign a new value to a variable. Values are in JSON format.";
|
||||
|
||||
int x = 1;
|
||||
|
||||
double y = 3.14;
|
||||
|
||||
std::vector<int> v{ 1, 2, 3 };
|
||||
|
||||
std::map<std::string, double> m{ { "BTC", 44898.68 }, { "ETH", 1386.57 } };
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( globals, (), (help, x, y, v, m) )
|
||||
|
||||
int main()
|
||||
{
|
||||
globals g_;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
std::cout << "\n> ";
|
||||
|
||||
std::string line;
|
||||
std::getline( std::cin, line );
|
||||
|
||||
try
|
||||
{
|
||||
std::size_t i = line.find( '=' );
|
||||
|
||||
if( i != std::string::npos )
|
||||
{
|
||||
set( g_, line.substr( 0, i ), boost::json::parse( line.substr( i + 1 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << get( g_, line ) << std::endl;
|
||||
}
|
||||
}
|
||||
catch( std::exception const& x )
|
||||
{
|
||||
std::cout << "Error: " << x.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
example/equality.cpp
Normal file
73
example/equality.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 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/variant2/variant.hpp>
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::describe;
|
||||
|
||||
namespace app
|
||||
{
|
||||
template<class T,
|
||||
class Bd = describe_bases<T, mod_any_access>,
|
||||
class Md = describe_members<T, mod_any_access>>
|
||||
bool operator==( T const& t1, T const& t2 )
|
||||
{
|
||||
bool r = true;
|
||||
|
||||
boost::mp11::mp_for_each<Bd>([&](auto D){
|
||||
|
||||
using B = typename decltype(D)::type;
|
||||
r = r && (B const&)t1 == (B const&)t2;
|
||||
|
||||
});
|
||||
|
||||
boost::mp11::mp_for_each<Md>([&](auto D){
|
||||
|
||||
r = r && t1.*D.pointer == t2.*D.pointer;
|
||||
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct A
|
||||
{
|
||||
int x = 1;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(A, (), (x))
|
||||
|
||||
struct B
|
||||
{
|
||||
int y = 2;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(B, (), (y))
|
||||
|
||||
struct C
|
||||
{
|
||||
std::vector<boost::variant2::variant<A, B>> v;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(C, (), (v))
|
||||
|
||||
} // namespace app
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
app::C c1, c2, c3;
|
||||
|
||||
c1.v.push_back( app::A{} );
|
||||
c2.v.push_back( app::A{} );
|
||||
c3.v.push_back( app::B{} );
|
||||
|
||||
std::cout << std::boolalpha
|
||||
<< ( c1 == c2 ) << ' '
|
||||
<< ( c1 == c3 ) << std::endl;
|
||||
}
|
||||
72
example/hash_value.cpp
Normal file
72
example/hash_value.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2021 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/container_hash/hash.hpp>
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::describe;
|
||||
|
||||
namespace app
|
||||
{
|
||||
|
||||
template<class T,
|
||||
class Bd = describe_bases<T, mod_any_access>,
|
||||
class Md = describe_members<T, mod_any_access>>
|
||||
std::size_t hash_value( T const & t )
|
||||
{
|
||||
std::size_t r = 0;
|
||||
|
||||
boost::mp11::mp_for_each<Bd>([&](auto D){
|
||||
|
||||
using B = typename decltype(D)::type;
|
||||
boost::hash_combine( r, (B const&)t );
|
||||
|
||||
});
|
||||
|
||||
boost::mp11::mp_for_each<Md>([&](auto D){
|
||||
|
||||
boost::hash_combine( r, t.*D.pointer );
|
||||
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct A
|
||||
{
|
||||
int x = 1;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(A, (), (x))
|
||||
|
||||
struct B
|
||||
{
|
||||
int y = 2;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(B, (), (y))
|
||||
|
||||
struct C
|
||||
{
|
||||
std::vector<boost::variant2::variant<A, B>> v;
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(C, (), (v))
|
||||
|
||||
} // namespace app
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
app::C c;
|
||||
|
||||
c.v.push_back( app::A{} );
|
||||
c.v.push_back( app::B{} );
|
||||
|
||||
std::cout << boost::hash<app::C>()( c ) << std::endl;
|
||||
}
|
||||
@@ -12,7 +12,8 @@
|
||||
[[noreturn]] void throw_invalid_name( char const * name, char const * type )
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string( "Invalid enumerator name '" ) + name + "' for enum type '" + type + "'" );
|
||||
std::string( "Invalid enumerator name '" ) + name
|
||||
+ "' for enum type '" + type + "'" );
|
||||
}
|
||||
|
||||
template<class E> E string_to_enum( char const * name )
|
||||
|
||||
@@ -129,10 +129,10 @@ template<class T, unsigned M> using describe_members = mp11::mp_eval_if_c<(M & m
|
||||
template<unsigned M> struct member_filter
|
||||
{
|
||||
template<class T> using fn = mp11::mp_bool<
|
||||
( M & mod_any_access & T::modifiers ) != 0 &&
|
||||
( M & mod_static ) == ( T::modifiers & mod_static ) &&
|
||||
( M & mod_function ) == ( T::modifiers & mod_function ) &&
|
||||
( M & mod_hidden ) >= ( T::modifiers & mod_hidden )
|
||||
(M & mod_any_access & T::modifiers) != 0 &&
|
||||
( (M & mod_any_member) != 0 || (M & mod_static) == (T::modifiers & mod_static) ) &&
|
||||
( (M & mod_any_member) != 0 || (M & mod_function) == (T::modifiers & mod_function) ) &&
|
||||
(M & mod_hidden) >= (T::modifiers & mod_hidden)
|
||||
>;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@ enum modifiers
|
||||
mod_virtual = 8,
|
||||
mod_static = 16,
|
||||
mod_function = 32,
|
||||
mod_inherited = 64,
|
||||
mod_hidden = 128,
|
||||
mod_any_member = 64,
|
||||
mod_inherited = 128,
|
||||
mod_hidden = 256,
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_ENUM(modifiers,
|
||||
@@ -31,6 +32,7 @@ BOOST_DESCRIBE_ENUM(modifiers,
|
||||
mod_virtual,
|
||||
mod_static,
|
||||
mod_function,
|
||||
mod_any_member,
|
||||
mod_inherited,
|
||||
mod_hidden);
|
||||
|
||||
|
||||
11
test/CMakeLists.txt
Normal file
11
test/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright 2018, 2021 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
|
||||
|
||||
if(HAVE_BOOST_TEST)
|
||||
|
||||
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::describe Boost::core)
|
||||
|
||||
endif()
|
||||
10
test/Jamfile
10
test/Jamfile
@@ -36,7 +36,10 @@ run members_test3.cpp ;
|
||||
run members_test4.cpp ;
|
||||
run members_test5.cpp ;
|
||||
run members_test6.cpp ;
|
||||
run members_test7.cpp : : : <toolset>msvc-14.0:<build>no ;
|
||||
run members_test7.cpp
|
||||
: : : <toolset>msvc-14.0:<build>no ;
|
||||
run members_test8.cpp ;
|
||||
|
||||
run overloaded_test.cpp ;
|
||||
run overloaded_test2.cpp ;
|
||||
|
||||
@@ -45,6 +48,8 @@ compile test_d_type.cpp ;
|
||||
compile-fail enum_struct_fail.cpp ;
|
||||
compile-fail struct_enum_fail.cpp ;
|
||||
|
||||
run class_template_test.cpp ;
|
||||
|
||||
obj describe_cxx14 : describe_cxx14.cpp ;
|
||||
explicit describe_cxx14 ;
|
||||
|
||||
@@ -62,3 +67,6 @@ run ../example/to_json.cpp : : : $(CXX14) $(JSON) ;
|
||||
run ../example/from_json.cpp : : : $(CXX14) $(JSON) ;
|
||||
run ../example/serialization.cpp : : : $(CXX14) $(SERIALIZATION) ;
|
||||
run ../example/json_rpc.cpp : : : $(CXX14) $(JSON) ;
|
||||
run ../example/hash_value.cpp : : : $(CXX14) ;
|
||||
run ../example/equality.cpp : : : $(CXX14) ;
|
||||
link ../example/console.cpp : $(CXX14) $(JSON) ;
|
||||
|
||||
143
test/class_template_test.cpp
Normal file
143
test/class_template_test.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2020, 2021 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/describe/bases.hpp>
|
||||
#include <boost/describe/members.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
template<class A1, class A2> struct X
|
||||
{
|
||||
A1 a1;
|
||||
A2 a2;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(X, (), (a1, a2), (), ())
|
||||
};
|
||||
|
||||
template<class B1, class B2> class Y
|
||||
{
|
||||
private:
|
||||
|
||||
B1 b1;
|
||||
B2 b2;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(Y, (), (), (), (b1, b2))
|
||||
};
|
||||
|
||||
template<class T1, class T2> class Z: public X<T1, T2>
|
||||
{
|
||||
private:
|
||||
|
||||
// error: declaration of 'typedef struct X<T1, T2> Z<T1, T2>::X' changes meaning of 'X' (g++)
|
||||
// typedef X<T1, T2> X;
|
||||
|
||||
typedef X<T1, T2> XB;
|
||||
|
||||
protected:
|
||||
|
||||
Y<T1, T2> y;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(Z, (XB), (), (y), ())
|
||||
};
|
||||
|
||||
#if !defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
|
||||
int main() {}
|
||||
|
||||
#elif defined(BOOST_MSVC) && BOOST_MSVC < 1920
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is below 1920")
|
||||
int main() {}
|
||||
|
||||
#elif defined(BOOST_MSVC) && BOOST_MSVC >= 1920 && BOOST_MSVC < 1930 && _MSVC_LANG <= 201703L
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is 192x and _MSVC_LANG is 201703L or below")
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/mp11.hpp>
|
||||
using namespace boost::mp11;
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::describe;
|
||||
using namespace boost::mp11;
|
||||
|
||||
{
|
||||
using L = describe_members<X<int, float>, mod_any_access>;
|
||||
|
||||
BOOST_TEST_EQ( mp_size<L>::value, 2 );
|
||||
|
||||
using D1 = mp_at_c<L, 0>;
|
||||
using D2 = mp_at_c<L, 1>;
|
||||
|
||||
BOOST_TEST( D1::pointer == (&X<int, float>::a1) );
|
||||
BOOST_TEST_CSTR_EQ( D1::name, "a1" );
|
||||
BOOST_TEST_EQ( D1::modifiers, mod_public );
|
||||
|
||||
BOOST_TEST( D2::pointer == (&X<int, float>::a2) );
|
||||
BOOST_TEST_CSTR_EQ( D2::name, "a2" );
|
||||
BOOST_TEST_EQ( D2::modifiers, mod_public );
|
||||
}
|
||||
|
||||
{
|
||||
using L = describe_members<Y<int, float>, mod_any_access>;
|
||||
|
||||
BOOST_TEST_EQ( mp_size<L>::value, 2 );
|
||||
|
||||
using D1 = mp_at_c<L, 0>;
|
||||
using D2 = mp_at_c<L, 1>;
|
||||
|
||||
// BOOST_TEST( D1::pointer == (&Y<int, float>::b1) );
|
||||
BOOST_TEST_CSTR_EQ( D1::name, "b1" );
|
||||
BOOST_TEST_EQ( D1::modifiers, mod_private );
|
||||
|
||||
// BOOST_TEST( D2::pointer == (&Y<int, float>::b2) );
|
||||
BOOST_TEST_CSTR_EQ( D2::name, "b2" );
|
||||
BOOST_TEST_EQ( D2::modifiers, mod_private );
|
||||
}
|
||||
|
||||
{
|
||||
using L = describe_members<Z<int, float>, mod_any_access>;
|
||||
|
||||
BOOST_TEST_EQ( mp_size<L>::value, 1 );
|
||||
|
||||
using D1 = mp_at_c<L, 0>;
|
||||
|
||||
// BOOST_TEST( D1::pointer == (&Z<int, float>::y) );
|
||||
BOOST_TEST_CSTR_EQ( D1::name, "y" );
|
||||
BOOST_TEST_EQ( D1::modifiers, mod_protected );
|
||||
}
|
||||
|
||||
{
|
||||
using L = describe_members<Z<int, float>, mod_any_access | mod_inherited>;
|
||||
|
||||
BOOST_TEST_EQ( mp_size<L>::value, 3 );
|
||||
|
||||
using D1 = mp_at_c<L, 0>;
|
||||
using D2 = mp_at_c<L, 1>;
|
||||
using D3 = mp_at_c<L, 2>;
|
||||
|
||||
BOOST_TEST( D1::pointer == (&X<int, float>::a1) );
|
||||
BOOST_TEST_CSTR_EQ( D1::name, "a1" );
|
||||
BOOST_TEST_EQ( D1::modifiers, mod_public | mod_inherited );
|
||||
|
||||
BOOST_TEST( D2::pointer == (&X<int, float>::a2) );
|
||||
BOOST_TEST_CSTR_EQ( D2::name, "a2" );
|
||||
BOOST_TEST_EQ( D2::modifiers, mod_public | mod_inherited );
|
||||
|
||||
// BOOST_TEST( D3::pointer == (&Z<int, float>::y) );
|
||||
BOOST_TEST_CSTR_EQ( D3::name, "y" );
|
||||
BOOST_TEST_EQ( D3::modifiers, mod_protected );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif // !defined(BOOST_DESCRIBE_CXX14)
|
||||
67
test/members_test8.cpp
Normal file
67
test/members_test8.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2020, 2021 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/describe/members.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct A
|
||||
{
|
||||
int m1;
|
||||
static int m2;
|
||||
int f1() const { return m1; }
|
||||
static int f2() { return m2; }
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT(A, (), (m1, m2, f1, f2))
|
||||
|
||||
int A::m2;
|
||||
|
||||
#if !defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/mp11.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::describe;
|
||||
using namespace boost::mp11;
|
||||
|
||||
{
|
||||
using L = describe_members<A, mod_any_access | mod_any_member>;
|
||||
|
||||
BOOST_TEST_EQ( mp_size<L>::value, 4 );
|
||||
|
||||
using D1 = mp_at_c<L, 0>;
|
||||
using D2 = mp_at_c<L, 1>;
|
||||
using D3 = mp_at_c<L, 2>;
|
||||
using D4 = mp_at_c<L, 3>;
|
||||
|
||||
BOOST_TEST( D1::pointer == &A::m1 );
|
||||
BOOST_TEST_CSTR_EQ( D1::name, "m1" );
|
||||
BOOST_TEST_EQ( D1::modifiers, mod_public );
|
||||
|
||||
BOOST_TEST( D2::pointer == &A::m2 );
|
||||
BOOST_TEST_CSTR_EQ( D2::name, "m2" );
|
||||
BOOST_TEST_EQ( D2::modifiers, mod_public | mod_static );
|
||||
|
||||
BOOST_TEST( D3::pointer == &A::f1 );
|
||||
BOOST_TEST_CSTR_EQ( D3::name, "f1" );
|
||||
BOOST_TEST_EQ( D3::modifiers, mod_public | mod_function );
|
||||
|
||||
BOOST_TEST( D4::pointer == &A::f2 );
|
||||
BOOST_TEST_CSTR_EQ( D4::name, "f2" );
|
||||
BOOST_TEST_EQ( D4::modifiers, mod_public | mod_static | mod_function );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif // !defined(BOOST_DESCRIBE_CXX14)
|
||||
Reference in New Issue
Block a user