Compare commits

...

25 Commits

Author SHA1 Message Date
Peter Dimov
2fc0e817ad Document descriptor_by_pointer 2021-10-27 06:24:09 +03:00
Peter Dimov
84fe8aa21e Add descriptor_by_pointer 2021-10-27 06:09:54 +03:00
Peter Dimov
003b2bdc50 Document descriptor_by_name 2021-10-27 05:42:38 +03:00
Peter Dimov
8437f2e62e Fix msvc-14.0 2021-10-27 04:31:35 +03:00
Peter Dimov
448174f346 Add descriptor_by_name 2021-10-27 04:13:29 +03:00
Peter Dimov
2935bca3b1 Update README, implementation section 2021-10-26 18:46:12 +03:00
Peter Dimov
e407d4da19 Document operators 2021-10-26 17:39:59 +03:00
Peter Dimov
2accb05ce5 Reset os.width in operator<< 2021-10-26 17:32:21 +03:00
Peter Dimov
128e3667d6 Add operators.hpp 2021-10-26 07:09:30 +03:00
Peter Dimov
8cf28d7b6e Include enum_from_string.hpp in describe.hpp 2021-10-26 06:21:56 +03:00
Peter Dimov
7397e8d66a Document enum_from_string 2021-10-26 05:40:26 +03:00
Peter Dimov
c3f16f3332 Add enum_from_string.hpp 2021-10-26 05:33:14 +03:00
Peter Dimov
890c1afcda Bump workaround in class_template_test.cpp 2021-10-26 04:18:37 +03:00
Peter Dimov
caa4cb6bf0 Bump workarounds in members_test7.cpp 2021-10-26 04:17:26 +03:00
Peter Dimov
ffa4790292 Add msvc-14.3 to ci.yml 2021-10-26 04:15:50 +03:00
Peter Dimov
f7d2f12cd4 Document enum_to_string 2021-10-26 04:13:18 +03:00
Peter Dimov
53d577428e Make enum_to_string noexcept 2021-10-26 04:12:58 +03:00
Peter Dimov
9c351a463f Add enum_to_string.hpp 2021-10-25 20:22:14 +03:00
Peter Dimov
af01484087 Document has_* 2021-10-25 20:08:13 +03:00
Peter Dimov
d5e79ee67d Remove superfluous semicolons 2021-10-25 19:53:53 +03:00
Peter Dimov
300ea0bebe Add has_describe_members 2021-10-25 18:45:26 +03:00
Peter Dimov
5a4c425f32 Add has_describe_bases 2021-10-25 18:40:38 +03:00
Peter Dimov
fe23aeeee4 Update ci.yml 2021-10-25 18:01:19 +03:00
Peter Dimov
daaec68db6 Update ci.yml 2021-10-25 17:40:36 +03:00
Peter Dimov
b6c41956ec Add has_describe_enumerators 2021-10-25 17:36:58 +03:00
31 changed files with 1386 additions and 66 deletions

View File

@@ -19,18 +19,15 @@ jobs:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-16.04
os: ubuntu-18.04
install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.9
- toolset: gcc-5
cxxstd: "03,11,14,14-gnu,1z,1z-gnu"
os: ubuntu-16.04
os: ubuntu-18.04
install: g++-5
- toolset: gcc-6
cxxstd: "03,11,14,14-gnu,1z,1z-gnu"
os: ubuntu-16.04
os: ubuntu-18.04
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,14-gnu,17,17-gnu"
@@ -41,48 +38,29 @@ jobs:
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
os: ubuntu-20.04
install: g++-10
- toolset: gcc-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
os: ubuntu-20.04
install: g++-11
- toolset: clang
compiler: clang++-3.5
cxxstd: "03,11"
os: ubuntu-16.04
install: clang-3.5
- toolset: clang
compiler: clang++-3.6
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.6
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.8
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-16.04
os: ubuntu-18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-16.04
os: ubuntu-18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
os: ubuntu-18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
@@ -96,7 +74,7 @@ jobs:
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17,2a"
cxxstd: "03,11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
@@ -108,14 +86,17 @@ jobs:
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-12
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
@@ -180,6 +161,15 @@ jobs:
addrmd: 32,64
cxxflags: "-Zc:preprocessor"
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: msvc-14.3
cxxstd: "14,17,latest"
addrmd: 32,64
cxxflags: "-Zc:preprocessor"
os: windows-2022
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64

View File

@@ -8,10 +8,10 @@ for more information and usage examples.
## Supported Compilers
* GCC 5 or later with `-std=c++14` or above
* Clang 3.6 or later with `-std=c++14` or above
* Clang 3.9 or later with `-std=c++14` or above
* Visual Studio 2015, 2017, 2019
Tested on [Travis](https://travis-ci.org/github/pdimov/describe/) and
Tested on [Github Actions](https://github.com/boostorg/describe/actions) and
[Appveyor](https://ci.appveyor.com/project/pdimov/describe).
## License

View File

@@ -9,6 +9,7 @@ Peter Dimov
:toc: left
:toclevels: 4
:idprefix:
:listing-caption: Code Example
:docinfo: private-footer
:source-highlighter: rouge
:source-language: c++
@@ -16,6 +17,7 @@ Peter Dimov
:leveloffset: +1
include::describe/overview.adoc[]
include::describe/changes.adoc[]
include::describe/enums.adoc[]
include::describe/classes.adoc[]
include::describe/examples.adoc[]

16
doc/describe/changes.adoc Normal file
View File

@@ -0,0 +1,16 @@
////
Copyright 2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#changes]
# Revision History
:idprefix:
## Changes in Boost 1.78.0
* Added `has_describe_enumerators`, `has_describe_bases`, `has_describe_members`.
* Added `enum_to_string`, `enum_from_string`.
* Added relational and stream insertion operators.
* Added `descriptor_by_name`, `descriptor_by_pointer`.

View File

@@ -8,5 +8,5 @@ https://www.boost.org/LICENSE_1_0.txt
# Copyright and License
:idprefix:
This documentation is copyright 2020 Peter Dimov and is distributed under
This documentation is copyright 2020, 2021 Peter Dimov and is distributed under
the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

View File

@@ -35,37 +35,36 @@ include::../../example/printing_enums_rt.cpp[lines=5..-1]
## enum_to_string
This example shows a function that, given an enumerator
value, returns its name.
Providing `enum_to_string` in a library is made difficult
by the fact that the desired behavior when the passed value
does not correspond to a named enumerator varies depending
on the specific use case. But, since defining the function
is trivial when `describe_enumerators` is available, every
user can easily have his own.
This specific example elects to return `"(unnamed)"` when
the enum value doesn't have a name.
value, returns its name. If the value does not correspond
to a named value, the function returns `"(unnamed)"`.
[source]
----
include::../../example/enum_to_string.cpp[lines=5..-1]
----
Since release 1.78.0, the library provides `enum_to_string`.
It differs from the one in the example by having a second
parameter that determines what should be returned when the
value doesn't correspond to a named enumerator.
[#example_string_to_enum]
## string_to_enum
The opposite of the previous example; returns an enumerator
value when given the enumerator name. The same problem exists
here with respect to the error handling strategy when the string
passed does not correspond to any enumerator name. This example
throws an exception.
value when given the enumerator name. When the string passed
does not correspond to any enumerator name, throws an exception.
[source]
----
include::../../example/string_to_enum.cpp[lines=5..-1]
----
Since release 1.78.0, the library provides `enum_from_string`.
It differs from the function in the example by signaling failure
by a `bool` return value instead of using exceptions. The
enumerator value is assigned to the output argument.
[#example_print_function]
## Defining a Universal Print Function
@@ -86,6 +85,27 @@ change its state and hence cannot violate its invariant.)
include::../../example/print_function.cpp[lines=5..-1]
----
Since release 1.78.0, this universal `operator<<` is supplied
by the library, in the `boost::describe::operators` namespace.
It's enabled by means of a using declaration in the namespace
containing the described application types, like in the example
below:
```
namespace app
{
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
using boost::describe::operators::operator<<;
}
```
[#example_hash_value]
## Implementing hash_value
@@ -117,6 +137,30 @@ to all annotated classes also defined in `app`.
include::../../example/equality.cpp[lines=5..-1]
----
Since release 1.78.0, this universal `operator==` is supplied
by the library, in the `boost::describe::operators` namespace.
It's enabled by means of a using declaration in the namespace
containing the described application types, like in the example
below:
```
namespace app
{
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
using boost::describe::operators::operator==;
}
```
The rest of the relational operators are also provided and can
be enabled similarly.
[#example_to_json]
## Automatic Conversion to JSON

View File

@@ -15,11 +15,11 @@ https://boost.org/libs/mp11[Boost.Mp11].
## Supported Compilers
* GCC 5 or later with `-std=c++14` or above
* Clang 3.6 or later with `-std=c++14` or above
* Clang 3.9 or later with `-std=c++14` or above
* Visual Studio 2015, 2017, 2019
Tested on https://travis-ci.org/github/pdimov/describe[Travis] and
https://ci.appveyor.com/project/pdimov/describe[Appveyor].
Tested on https://github.com/boostorg/describe/actions[Github Actions]
and https://ci.appveyor.com/project/pdimov/describe[Appveyor].
## Limitations

View File

@@ -96,6 +96,8 @@ namespace describe {
template<class E> using describe_enumerators = /*...*/;
template<class E> using has_describe_enumerators = /*...*/;
} }
```
@@ -116,6 +118,14 @@ struct Di
```
where `vi` is the i-th enumerator.
If `E` is not a described enumeration type, `describe_enumerators<E>` causes
a substitution failure.
### has_describe_enumerators<E>
`has_describe_enumerators<E>::value` is `true` when `E` is a described
enumeration type, `false` otherwise.
## <boost/describe/class.hpp>
```
@@ -232,6 +242,8 @@ namespace describe {
template<class T, unsigned M> using describe_bases = /*...*/;
template<class T> using has_describe_bases = /*...*/;
} }
```
@@ -257,6 +269,18 @@ where `type` is the type of the base class, and `modifiers` are a bitwise-or
combination of `mod_public`, `mod_protected`, `mod_private`, and `mod_virtual`
that reflects the properties of the base class.
If `T` is not a described class type, `describe_bases<T, M>` causes a
substitution failure.
### has_describe_bases<T>
`has_describe_bases<T>::value` is `true` when `T` is a described class type,
`false` otherwise.
Since the library does not provide a way to describe bases and members separately,
`has_describe_bases` and `has_describe_members` are, in practice, synonyms. They
are provided separately for consistency.
## <boost/describe/members.hpp>
```
@@ -265,6 +289,8 @@ namespace describe {
template<class T, unsigned M> using describe_members = /*...*/;
template<class T> using has_describe_members = /*...*/;
} }
```
@@ -294,6 +320,189 @@ member, and `modifiers` are a bitwise-or combination of `mod_public`,
`mod_protected`, `mod_private`, `mod_static`, `mod_function`, `mod_inherited`,
and `mod_hidden` that reflects the properties of the member.
If `T` is not a described class type, `describe_members<T, M>` causes a
substitution failure.
### has_describe_members<T>
`has_describe_members<T>::value` is `true` when `T` is a described class type,
`false` otherwise.
Since the library does not provide a way to describe bases and members separately,
`has_describe_bases` and `has_describe_members` are, in practice, synonyms. They
are provided separately for consistency.
## <boost/describe/enum_to_string.hpp>
```
namespace boost {
namespace describe {
template<class E> char const * enum_to_string( E e, char const * def ) noexcept;
} }
```
### enum_to_string
The function `enum_to_string` returns the name of the enumerator `e`. `E` must
be a described enumeration type. If `e` does not correspond to one of the described
values, the function returns `def`.
## <boost/describe/enum_from_string.hpp>
```
namespace boost {
namespace describe {
template<class E> bool enum_from_string( char const * name, E & e ) noexcept;
} }
```
### enum_from_string
The function `enum_from_string` assigns to `e` the enumerator value corresponding
to `name` and returns `true`. `E` must be a described enumeration type. If `name`
does not correspond to one of the described values, the function returns `false`.
## <boost/describe/operators.hpp>
```
namespace boost {
namespace describe {
namespace operators {
template<class T> bool operator==( T const& t1, T const& t2 );
template<class T> bool operator!=( T const& t1, T const& t2 );
template<class T> bool operator<( T const& t1, T const& t2 );
template<class T> bool operator>( T const& t1, T const& t2 );
template<class T> bool operator<=( T const& t1, T const& t2 );
template<class T> bool operator>=( T const& t1, T const& t2 );
template<class T, class Ch, class Tr>
std::basic_ostream<Ch, Tr>&
operator<<( std::basic_ostream<Ch, Tr>& os, T const& t );
} } }
```
The header `<boost/describe/operators.hpp>` defines generic operators for
described class types. They are used by bringing them into the namespace
containing the described types via a using declaration, as in the example
below:
```
namespace app
{
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
}
```
### operator==
If all bases and members compare equal, returns `true`, otherwise `false`.
### operator!=
Returns the negation of `operator==`.
### operator<
Performs a lexicographical comparison over the bases and members in sequence
using `operator<` and returns the result.
### operator>
Returns the result of `operator<` with the arguments reversed.
### operator\<=
Returns the negated result of `operator>`.
### operator>=
Returns the negated result of `operator<`.
### operator<<
Outputs a representation of `t` to `os` by recursively using `operator<<`
to output all bases and then all members.
## <boost/describe/descriptor_by_name.hpp>
```
namespace boost {
namespace describe {
#define BOOST_DESCRIBE_MAKE_NAME(s) /*...*/
template<class L, class N> using descriptor_by_name = /*...*/;
} }
```
### BOOST_DESCRIBE_MAKE_NAME
The macro `BOOST_DESCRIBE_MAKE_NAME` creates a type that identifies the
name given as an argument. It should be used as follows:
```
using N = BOOST_DESCRIBE_MAKE_NAME(some_member);
```
### descriptor_by_name
`descriptor_by_name<L, N>` searches the descriptor list `L` for the member
with the name identified by `N`. `N` should be a type created by
`BOOST_DESCRIBE_MAKE_NAME` as in the above example. `L` is intended to be
a list returned by `describe_members`, although since enumerator descriptors
also have `::name`, a list returned by `describe_enumerators` will work as
well.
.Using descriptor_by_name
```
using L = describe_members<SomeType, mod_any_access>;
using N = BOOST_DESCRIBE_MAKE_NAME(some_member);
using D = descriptor_by_name<L, N>; // descriptor for SomeType::some_member
```
## <boost/describe/descriptor_by_pointer.hpp>
```
namespace boost {
namespace describe {
template<class L, auto Pm> using descriptor_by_pointer = /*...*/;
} }
```
### descriptor_by_pointer
`descriptor_by_pointer<L, Pm>` searches the descriptor list `L` for the member
pointer `Pm`. `L` should be a list returned by `describe_members`.
Since `auto` template parameters are a {cpp}17 feature, using
`descriptor_by_pointer` requires {cpp}17.
.Using descriptor_by_pointer
```
using L = describe_members<X, mod_any_access>;
using D = descriptor_by_pointer<L, &X::a>; // descriptor for X::a
```
## <boost/describe.hpp>
This convenience header includes all the headers previously

View File

@@ -11,5 +11,10 @@
#include <boost/describe/enum.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/modifiers.hpp>
#include <boost/describe/enum_to_string.hpp>
#include <boost/describe/enum_from_string.hpp>
#include <boost/describe/operators.hpp>
#include <boost/describe/descriptor_by_name.hpp>
#include <boost/describe/descriptor_by_pointer.hpp>
#endif // #ifndef BOOST_DESCRIBE_HPP_INCLUDED

View File

@@ -1,16 +1,18 @@
#ifndef BOOST_DESCRIBE_BASES_HPP_INCLUDED
#define BOOST_DESCRIBE_BASES_HPP_INCLUDED
// 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
#include <boost/describe/modifiers.hpp>
#include <boost/describe/detail/void_t.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
#include <boost/mp11/algorithm.hpp>
#include <type_traits>
namespace boost
{
@@ -26,10 +28,20 @@ template<unsigned M> struct base_filter
template<class T> using fn = mp11::mp_bool< ( M & mod_any_access & T::modifiers ) != 0 >;
};
template<class T, class En = void> struct has_describe_bases: std::false_type
{
};
template<class T> struct has_describe_bases<T, void_t<_describe_bases<T>>>: std::true_type
{
};
} // namespace detail
template<class T, unsigned M> using describe_bases = mp11::mp_copy_if_q<detail::_describe_bases<T>, detail::base_filter<M>>;
template<class T> using has_describe_bases = detail::has_describe_bases<T>;
} // namespace describe
} // namespace boost

View File

@@ -0,0 +1,41 @@
#ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_NAME_HPP_INCLUDED
#define BOOST_DESCRIBE_DESCRIPTOR_BY_NAME_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/cx_streq.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/bind.hpp>
#include <boost/mp11/integral.hpp>
namespace boost
{
namespace describe
{
namespace detail
{
template<class D, class N> using match_by_name = mp11::mp_bool<cx_streq(N::name(), D::name)>;
#define BOOST_DESCRIBE_MAKE_NAME_IMPL2(s, k) struct _boost_name_##s##_##k { static constexpr char const * name() { return #s; } }
#define BOOST_DESCRIBE_MAKE_NAME_IMPL(s, k) BOOST_DESCRIBE_MAKE_NAME_IMPL2(s, k)
} // namespace detail
#define BOOST_DESCRIBE_MAKE_NAME(s) BOOST_DESCRIBE_MAKE_NAME_IMPL(s, __LINE__)
template<class L, class N> using descriptor_by_name = mp11::mp_at<L, mp11::mp_find_if_q<L, mp11::mp_bind_back<detail::match_by_name, N>>>;
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_NAME_HPP_INCLUDED

View File

@@ -0,0 +1,48 @@
#ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_POINTER_HPP_INCLUDED
#define BOOST_DESCRIBE_DESCRIPTOR_BY_POINTER_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/bind.hpp>
#include <boost/mp11/integral.hpp>
namespace boost
{
namespace describe
{
namespace detail
{
template<class Pm> constexpr bool cx_pmeq( Pm p1, Pm p2 )
{
return p1 == p2;
}
template<class Pm1, class Pm2> constexpr bool cx_pmeq( Pm1, Pm2 )
{
return false;
}
template<auto Pm> struct match_by_pointer
{
template<class D> using fn = mp11::mp_bool< cx_pmeq( D::pointer, Pm ) >;
};
} // namespace detail
template<class L, auto Pm> using descriptor_by_pointer = mp11::mp_at<L, mp11::mp_find_if_q<L, detail::match_by_pointer<Pm>>>;
} // namespace describe
} // namespace boost
#endif // __cpp_nontype_template_parameter_auto
#endif // #ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_POINTER_HPP_INCLUDED

View File

@@ -0,0 +1,30 @@
#ifndef BOOST_DESCRIBE_DETAIL_CX_STREQ_HPP_INCLUDED
#define BOOST_DESCRIBE_DETAIL_CX_STREQ_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
namespace boost
{
namespace describe
{
namespace detail
{
constexpr bool cx_streq( char const * s1, char const * s2 )
{
return s1[0] == s2[0] && ( s1[0] == 0 || cx_streq( s1 + 1, s2 + 1 ) );
}
} // namespace detail
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX11)
#endif // #ifndef BOOST_DESCRIBE_DETAIL_CX_STREQ_HPP_INCLUDED

View File

@@ -0,0 +1,32 @@
#ifndef BOOST_DESCRIBE_DETAIL_VOID_T_HPP_INCLUDED
#define BOOST_DESCRIBE_DETAIL_VOID_T_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
namespace boost
{
namespace describe
{
namespace detail
{
template<class...> struct make_void
{
using type = void;
};
template<class... T> using void_t = typename make_void<T...>::type;
} // namespace detail
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX11)
#endif // #ifndef BOOST_DESCRIBE_DETAIL_VOID_T_HPP_INCLUDED

View File

@@ -0,0 +1,44 @@
#ifndef BOOST_DESCRIBE_ENUM_FROM_STRING_HPP_INCLUDED
#define BOOST_DESCRIBE_ENUM_FROM_STRING_HPP_INCLUDED
// 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/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/describe/enumerators.hpp>
#include <boost/mp11/algorithm.hpp>
#include <cstring>
namespace boost
{
namespace describe
{
template<class E, class De = describe_enumerators<E>>
bool enum_from_string( char const* name, E& e ) noexcept
{
bool found = false;
mp11::mp_for_each<De>([&](auto D){
if( !found && std::strcmp( D.name, name ) == 0 )
{
found = true;
e = D.value;
}
});
return found;
}
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_ENUM_FROM_STRING_HPP_INCLUDED

View File

@@ -0,0 +1,39 @@
#ifndef BOOST_DESCRIBE_ENUM_TO_STRING_HPP_INCLUDED
#define BOOST_DESCRIBE_ENUM_TO_STRING_HPP_INCLUDED
// 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/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/describe/enumerators.hpp>
#include <boost/mp11/algorithm.hpp>
namespace boost
{
namespace describe
{
template<class E, class De = describe_enumerators<E>>
char const * enum_to_string( E e, char const* def ) noexcept
{
char const * r = def;
mp11::mp_for_each<De>([&](auto D){
if( e == D.value ) r = D.name;
});
return r;
}
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_ENUM_TO_STRING_HPP_INCLUDED

View File

@@ -1,21 +1,43 @@
#ifndef BOOST_DESCRIBE_ENUMERATORS_HPP_INCLUDED
#define BOOST_DESCRIBE_ENUMERATORS_HPP_INCLUDED
// 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
#include <boost/describe/detail/void_t.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
#include <type_traits>
namespace boost
{
namespace describe
{
// describe_enumerators<E>
template<class E> using describe_enumerators = decltype( boost_enum_descriptor_fn( static_cast<E*>(0) ) );
// has_describe_enumerators<E>
namespace detail
{
template<class E, class En = void> struct has_describe_enumerators: std::false_type
{
};
template<class E> struct has_describe_enumerators<E, void_t<describe_enumerators<E>>>: std::true_type
{
};
} // namespace detail
template<class E> using has_describe_enumerators = detail::has_describe_enumerators<E>;
} // namespace describe
} // namespace boost

View File

@@ -7,6 +7,9 @@
#include <boost/describe/modifiers.hpp>
#include <boost/describe/bases.hpp>
#include <boost/describe/detail/void_t.hpp>
#include <boost/describe/detail/cx_streq.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
@@ -15,6 +18,7 @@
#include <boost/mp11/integral.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/bind.hpp>
#include <type_traits>
namespace boost
{
@@ -57,11 +61,6 @@ template<template<class...> class L, class T, class V> struct describe_inherited
using type = L<>;
};
constexpr bool cx_streq( char const * s1, char const * s2 )
{
return s1[0] == s2[0] && ( s1[0] == 0 || cx_streq( s1 + 1, s2 + 1 ) );
}
template<class D1, class D2> using name_matches = mp11::mp_bool< cx_streq( D1::name, D2::name ) >;
template<class D, class L> using name_is_hidden = mp11::mp_any_of_q<L, mp11::mp_bind_front<name_matches, D>>;
@@ -136,10 +135,22 @@ template<unsigned M> struct member_filter
>;
};
// has_describe_members
template<class T, class En = void> struct has_describe_members: std::false_type
{
};
template<class T> struct has_describe_members<T, void_t<_describe_members<T>>>: std::true_type
{
};
} // namespace detail
template<class T, unsigned M> using describe_members = mp11::mp_copy_if_q<detail::describe_members<T, M>, detail::member_filter<M>>;
template<class T> using has_describe_members = detail::has_describe_members<T>;
} // namespace describe
} // namespace boost

View File

@@ -0,0 +1,170 @@
#ifndef BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED
#define BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED
// 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/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/describe/bases.hpp>
#include <boost/describe/members.hpp>
#include <boost/describe/modifiers.hpp>
#include <boost/mp11/algorithm.hpp>
#include <type_traits>
#include <iosfwd>
namespace boost
{
namespace describe
{
namespace detail
{
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
bool eq( T const& t1, T const& t2 )
{
bool r = true;
mp11::mp_for_each<Bd>([&](auto D){
using B = typename decltype(D)::type;
r = r && (B const&)t1 == (B const&)t2;
});
mp11::mp_for_each<Md>([&](auto D){
r = r && t1.*D.pointer == t2.*D.pointer;
});
return r;
}
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
bool lt( T const& t1, T const& t2 )
{
int r = 0;
mp11::mp_for_each<Bd>([&](auto D){
using B = typename decltype(D)::type;
if( r == 0 && (B const&)t1 < (B const&)t2 ) r = -1;
if( r == 0 && (B const&)t2 < (B const&)t1 ) r = +1;
});
mp11::mp_for_each<Md>([&](auto D){
if( r == 0 && t1.*D.pointer < t2.*D.pointer ) r = -1;
if( r == 0 && t2.*D.pointer < t1.*D.pointer ) r = +1;
});
return r < 0;
}
template<class Os, class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
void print( Os& os, T const& t )
{
os << "{";
bool first = true;
mp11::mp_for_each<Bd>([&](auto D){
if( !first ) { os << ", "; }
first = false;
using B = typename decltype(D)::type;
os << (B const&)t;
});
mp11::mp_for_each<Md>([&](auto D){
if( !first ) { os << ", "; }
first = false;
os << "." << D.name << " = " << t.*D.pointer;
});
os << "}";
}
} // namespace detail
namespace operators
{
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
operator==( T const& t1, T const& t2 )
{
return detail::eq( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
operator!=( T const& t1, T const& t2 )
{
return !detail::eq( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
operator<( T const& t1, T const& t2 )
{
return detail::lt( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
operator>=( T const& t1, T const& t2 )
{
return !detail::lt( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
operator>( T const& t1, T const& t2 )
{
return detail::lt( t2, t1 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
operator<=( T const& t1, T const& t2 )
{
return !detail::lt( t2, t1 );
}
template<class T, class Ch, class Tr> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value,
std::basic_ostream<Ch, Tr>&>
operator<<( std::basic_ostream<Ch, Tr>& os, T const& t )
{
os.width( 0 );
detail::print( os, t );
return os;
}
} // namespace operators
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED

View File

@@ -50,6 +50,21 @@ compile-fail struct_enum_fail.cpp ;
run class_template_test.cpp ;
run has_enumerators_test.cpp ;
run has_bases_test.cpp ;
run has_members_test.cpp ;
run enum_to_string_test.cpp ;
run enum_from_string_test.cpp ;
run operator_eq_test.cpp ;
run operator_lt_test.cpp ;
run descriptor_by_name_test.cpp ;
run descriptor_by_pointer_test.cpp ;
# examples
obj describe_cxx14 : describe_cxx14.cpp ;
explicit describe_cxx14 ;

View File

@@ -54,9 +54,9 @@ int main() {}
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
#elif defined(BOOST_MSVC) && BOOST_MSVC >= 1920 && BOOST_MSVC < 1940 && _MSVC_LANG <= 201703L
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is 192x and _MSVC_LANG is 201703L or below")
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is 192x or 193x and _MSVC_LANG is 201703L or below")
int main() {}
#else

View File

@@ -0,0 +1,64 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/descriptor_by_name.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/members.hpp>
#include <boost/core/lightweight_test.hpp>
#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
struct X
{
int a = 1;
int b = 2;
};
BOOST_DESCRIBE_STRUCT(X, (), (a, b))
struct Y
{
int a = 1;
int c = 3;
};
BOOST_DESCRIBE_STRUCT(Y, (), (a, c))
int main()
{
{
using L = boost::describe::describe_members<X, boost::describe::mod_any_access>;
using Na = BOOST_DESCRIBE_MAKE_NAME( a );
using Da = boost::describe::descriptor_by_name<L, Na>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Nb = BOOST_DESCRIBE_MAKE_NAME( b );
using Db = boost::describe::descriptor_by_name<L, Nb>;
BOOST_TEST_CSTR_EQ( Db::name, "b" );
}
{
using L = boost::describe::describe_members<Y, boost::describe::mod_any_access>;
using Na = BOOST_DESCRIBE_MAKE_NAME( a );
using Da = boost::describe::descriptor_by_name<L, Na>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Nc = BOOST_DESCRIBE_MAKE_NAME( c );
using Dc = boost::describe::descriptor_by_name<L, Nc>;
BOOST_TEST_CSTR_EQ( Dc::name, "c" );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,65 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/descriptor_by_pointer.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/members.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(__cpp_nontype_template_parameter_auto) || __cpp_nontype_template_parameter_auto < 201606L
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because __cpp_nontype_template_parameter_auto is not defined")
int main() {}
#else
struct X
{
int a = 1;
float b = 3.14f;
};
BOOST_DESCRIBE_STRUCT(X, (), (a, b))
struct Y: public X
{
long a = 2;
double c = 3.14;
};
BOOST_DESCRIBE_STRUCT(Y, (X), (a, c))
int main()
{
using namespace boost::describe;
{
using L = describe_members<X, mod_any_access>;
using Da = descriptor_by_pointer<L, &X::a>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Db = descriptor_by_pointer<L, &X::b>;
BOOST_TEST_CSTR_EQ( Db::name, "b" );
}
{
using L = describe_members<Y, mod_any_access | mod_inherited>;
using Da = descriptor_by_pointer<L, &Y::a>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Db = descriptor_by_pointer<L, &Y::b>;
BOOST_TEST_CSTR_EQ( Db::name, "b" );
using Dc = descriptor_by_pointer<L, &Y::c>;
BOOST_TEST_CSTR_EQ( Dc::name, "c" );
}
return boost::report_errors();
}
#endif // __cpp_nontype_template_parameter_auto

View File

@@ -0,0 +1,62 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum_from_string.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/lightweight_test.hpp>
#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
enum E1 { v101 = 101, v102 = 102 };
BOOST_DESCRIBE_ENUM(E1, v101, v102)
enum class E2 { v201 = 201, v202 = 202 };
BOOST_DESCRIBE_ENUM(E2, v201, v202)
BOOST_DEFINE_ENUM(E3, v301, v302);
BOOST_DEFINE_ENUM_CLASS(E4, v401, v402)
int main()
{
using boost::describe::enum_from_string;
{
E1 w{};
BOOST_TEST( enum_from_string( "v101", w ) ) && BOOST_TEST_EQ( w, v101 );
BOOST_TEST( enum_from_string( "v102", w ) ) && BOOST_TEST_EQ( w, v102 );
BOOST_TEST_NOT( enum_from_string( "v103", w ) );
}
{
E2 w{};
BOOST_TEST( enum_from_string( "v201", w ) ) && BOOST_TEST_EQ( (int)w, (int)E2::v201 );
BOOST_TEST( enum_from_string( "v202", w ) ) && BOOST_TEST_EQ( (int)w, (int)E2::v202 );
BOOST_TEST_NOT( enum_from_string( "v203", w ) );
}
{
E3 w{};
BOOST_TEST( enum_from_string( "v301", w ) ) && BOOST_TEST_EQ( w, v301 );
BOOST_TEST( enum_from_string( "v302", w ) ) && BOOST_TEST_EQ( w, v302 );
BOOST_TEST_NOT( enum_from_string( "v303", w ) );
}
{
E4 w{};
BOOST_TEST( enum_from_string( "v401", w ) ) && BOOST_TEST_EQ( (int)w, (int)E4::v401 );
BOOST_TEST( enum_from_string( "v402", w ) ) && BOOST_TEST_EQ( (int)w, (int)E4::v402 );
BOOST_TEST_NOT( enum_from_string( "v403", w ) );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,41 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum_to_string.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/lightweight_test.hpp>
#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
enum E1 { v1 };
BOOST_DESCRIBE_ENUM(E1, v1)
enum class E2 { v2 };
BOOST_DESCRIBE_ENUM(E2, v2)
BOOST_DEFINE_ENUM(E3, v3);
BOOST_DEFINE_ENUM_CLASS(E4, v4)
int main()
{
using boost::describe::enum_to_string;
BOOST_TEST_CSTR_EQ( enum_to_string( v1, "" ), "v1" );
BOOST_TEST_CSTR_EQ( enum_to_string( E2::v2, "" ), "v2" );
BOOST_TEST_CSTR_EQ( enum_to_string( static_cast<E2>( 14 ), "__def__" ), "__def__" );
BOOST_TEST_CSTR_EQ( enum_to_string( v3, "" ), "v3" );
BOOST_TEST_CSTR_EQ( enum_to_string( E4::v4, "" ), "v4" );
BOOST_TEST_EQ( enum_to_string( static_cast<E4>( 14 ), 0 ), static_cast<char const*>( 0 ) );
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

55
test/has_bases_test.cpp Normal file
View File

@@ -0,0 +1,55 @@
// Copyright 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/class.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#else
struct X1 {};
BOOST_DESCRIBE_STRUCT(X1, (), ())
class X2
{
BOOST_DESCRIBE_CLASS(X2, (), (), (), ())
};
struct X3 {};
class X4 {};
union X5 {};
int main()
{
using boost::describe::has_describe_bases;
#if defined(BOOST_DESCRIBE_CXX14)
BOOST_TEST_TRAIT_TRUE((has_describe_bases<X1>));
BOOST_TEST_TRAIT_TRUE((has_describe_bases<X2>));
#else
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X1>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X2>));
#endif
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X3>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X4>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X5>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<int>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<void>));
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX11)

View File

@@ -0,0 +1,58 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enumerators.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#else
enum E1 { v1 };
BOOST_DESCRIBE_ENUM(E1, v1)
enum class E2 { v2 };
BOOST_DESCRIBE_ENUM(E2, v2)
BOOST_DEFINE_ENUM(E3, v3);
BOOST_DEFINE_ENUM_CLASS(E4, v4)
enum E5 { v5 };
enum class E6 { v6 };
int main()
{
using boost::describe::has_describe_enumerators;
#if defined(BOOST_DESCRIBE_CXX14)
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E1>));
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E2>));
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E3>));
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E4>));
#else
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E1>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E2>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E3>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E4>));
#endif
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E5>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E6>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<int>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<void>));
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX11)

55
test/has_members_test.cpp Normal file
View File

@@ -0,0 +1,55 @@
// Copyright 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_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#else
struct X1 {};
BOOST_DESCRIBE_STRUCT(X1, (), ())
class X2
{
BOOST_DESCRIBE_CLASS(X2, (), (), (), ())
};
struct X3 {};
class X4 {};
union X5 {};
int main()
{
using boost::describe::has_describe_members;
#if defined(BOOST_DESCRIBE_CXX14)
BOOST_TEST_TRAIT_TRUE((has_describe_members<X1>));
BOOST_TEST_TRAIT_TRUE((has_describe_members<X2>));
#else
BOOST_TEST_TRAIT_FALSE((has_describe_members<X1>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X2>));
#endif
BOOST_TEST_TRAIT_FALSE((has_describe_members<X3>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X4>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X5>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<int>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<void>));
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX11)

View File

@@ -59,7 +59,7 @@ int main()
using D1 = mp_at_c<L, 0>;
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1940)
// https://developercommunity.visualstudio.com/content/problem/1186002/constexpr-pointer-to-member-has-incorrect-value.html
BOOST_TEST( D1::pointer == &C::m2 );
#endif
@@ -79,7 +79,7 @@ int main()
BOOST_TEST_CSTR_EQ( D1::name, "m1" );
BOOST_TEST_EQ( D1::modifiers, mod_public | mod_inherited );
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1940)
BOOST_TEST( D2::pointer == &C::m2 );
#endif
BOOST_TEST_CSTR_EQ( D2::name, "m2" );

91
test/operator_eq_test.cpp Normal file
View File

@@ -0,0 +1,91 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/operators.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#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
namespace app
{
struct X
{
};
BOOST_DESCRIBE_STRUCT(X, (), ())
using boost::describe::operators::operator==;
using boost::describe::operators::operator<<;
struct Y
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(Y, (), (a))
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
struct Z: X, Y
{
int b = 4;
};
BOOST_DESCRIBE_STRUCT(Z, (X, Y), (b))
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
} // namespace app
int main()
{
using app::X;
{
X x1, x2;
BOOST_TEST_EQ( x1, x2 );
}
using app::Y;
{
Y y1, y2, y3;
y3.a = 2;
BOOST_TEST_EQ( y1, y2 );
BOOST_TEST_NE( y1, y3 );
}
using app::Z;
{
Z z1, z2, z3, z4;
z3.a = 2;
z4.b = 3;
BOOST_TEST_EQ( z1, z2 );
BOOST_TEST_NE( z1, z3 );
BOOST_TEST_NE( z1, z4 );
BOOST_TEST_NE( z3, z4 );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

99
test/operator_lt_test.cpp Normal file
View File

@@ -0,0 +1,99 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/operators.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#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
namespace app
{
struct X
{
};
BOOST_DESCRIBE_STRUCT(X, (), ())
using boost::describe::operators::operator<=;
using boost::describe::operators::operator>=;
using boost::describe::operators::operator<<;
struct Y
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(Y, (), (a))
using boost::describe::operators::operator<;
using boost::describe::operators::operator>;
using boost::describe::operators::operator<=;
using boost::describe::operators::operator>=;
using boost::describe::operators::operator<<;
struct Z: X, Y
{
int b = 4;
};
BOOST_DESCRIBE_STRUCT(Z, (X, Y), (b))
using boost::describe::operators::operator<;
using boost::describe::operators::operator>;
using boost::describe::operators::operator<=;
using boost::describe::operators::operator>=;
using boost::describe::operators::operator<<;
} // namespace app
#define TEST_EQ(x, y) BOOST_TEST_LE(x, y); BOOST_TEST_GE(x, y); BOOST_TEST_NOT((x) < (y)); BOOST_TEST_NOT((x) > (y))
#define TEST_LT(x, y) BOOST_TEST_LT(x, y); BOOST_TEST_LE(x, y); BOOST_TEST_GT(y, x); BOOST_TEST_GE(y, x)
int main()
{
using app::X;
{
X x1, x2;
TEST_EQ( x1, x2 );
}
using app::Y;
{
Y y1, y2, y3;
y3.a = 2;
TEST_EQ( y1, y2 );
TEST_LT( y1, y3 );
}
using app::Z;
{
Z z1, z2, z3, z4;
z3.a = 2;
z4.b = 3;
TEST_EQ( z1, z2 );
TEST_LT( z1, z3 );
TEST_LT( z4, z1 );
TEST_LT( z4, z3 );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)