Compare commits

...

7 Commits

Author SHA1 Message Date
Peter Dimov
811003ea0c g++ 4.8 doesn't like static union members either 2021-12-15 03:40:34 +02:00
Peter Dimov
bd8be41591 Add !is_union<T>::value to examples 2021-12-15 02:14:56 +02:00
Peter Dimov
f9477bc177 Disable operators for unions because their behavior is undefined 2021-12-15 02:00:20 +02:00
Peter Dimov
d98f4d1f40 Disable union tests for C++03 because static members are not allowed 2021-12-15 01:49:52 +02:00
Peter Dimov
2e3b6a6791 Test BOOST_DESCRIBE_CLASS with a union 2021-12-15 01:41:54 +02:00
Peter Dimov
fabf5c7115 Allow unions in BOOST_DESCRIBE_STRUCT (refs #21) 2021-12-15 01:33:06 +02:00
Peter Dimov
ec7aec2b3d Add msvc-14.0 to GHA 2021-12-11 20:15:03 +02:00
13 changed files with 262 additions and 18 deletions

View File

@@ -148,6 +148,10 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.1
cxxstd: "14,17,latest"
addrmd: 32,64

View File

@@ -13,7 +13,8 @@ namespace app
{
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
class Md = describe_members<T, mod_any_access>,
class En = std::enable_if_t<!std::is_union<T>::value> >
bool operator==( T const& t1, T const& t2 )
{
bool r = true;

View File

@@ -19,7 +19,7 @@ template<class T,
class D1 = boost::describe::describe_members<T,
boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value && !std::is_union<T>::value> >
T tag_invoke( boost::json::value_to_tag<T> const&, boost::json::value const& v )
{

View File

@@ -15,7 +15,8 @@ namespace app
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
class Md = describe_members<T, mod_any_access>,
class En = std::enable_if_t<!std::is_union<T>::value> >
std::size_t hash_value( T const & t )
{
std::size_t r = 0;

View File

@@ -10,7 +10,8 @@ using namespace boost::describe;
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
class Md = describe_members<T, mod_any_access>,
class En = std::enable_if_t<!std::is_union<T>::value> >
std::ostream& operator<<( std::ostream & os, T const & t )
{
os << "{";

View File

@@ -24,8 +24,8 @@ template<class Archive, class T,
class D3 = boost::describe::describe_members<T,
boost::describe::mod_public | boost::describe::mod_protected>,
class D4 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<
boost::mp11::mp_empty<D2>::value && boost::mp11::mp_empty<D4>::value> >
class En = std::enable_if_t< boost::mp11::mp_empty<D2>::value &&
boost::mp11::mp_empty<D4>::value && !std::is_union<T>::value> >
void serialize( Archive & ar, T & t, boost::serialization::version_type )
{

View File

@@ -13,8 +13,10 @@ auto struct_to_tuple_impl( T const& t, L<D...> )
return std::make_tuple( t.*D::pointer... );
}
template<class T, class Dm = desc::describe_members<T,
desc::mod_public | desc::mod_inherited>>
template<class T,
class Dm = desc::describe_members<T,
desc::mod_public | desc::mod_inherited>,
class En = std::enable_if_t<!std::is_union<T>::value> >
auto struct_to_tuple( T const& t )
{
return struct_to_tuple_impl( t, Dm() );

View File

@@ -16,7 +16,7 @@ template<class T,
class D1 = boost::describe::describe_members<T,
boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value && !std::is_union<T>::value> >
void tag_invoke( boost::json::value_from_tag const&, boost::json::value& v, T const & t )
{

View File

@@ -34,7 +34,7 @@ namespace describe
friend BOOST_DESCRIBE_PRIVATE_MEMBERS(C, BOOST_DESCRIBE_PP_UNPACK Private)
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members) \
static_assert(std::is_class<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
BOOST_DESCRIBE_BASES(C, BOOST_DESCRIBE_PP_UNPACK Bases) \
BOOST_DESCRIBE_PUBLIC_MEMBERS(C, BOOST_DESCRIBE_PP_UNPACK Members) \
BOOST_DESCRIBE_PROTECTED_MEMBERS(C) \
@@ -60,7 +60,7 @@ namespace describe
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PRIVATE_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Private)
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members) \
static_assert(std::is_class<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_BASES_(C BOOST_DESCRIBE_PP_UNPACK Bases) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Members) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PROTECTED_MEMBERS_(C) \

View File

@@ -109,49 +109,49 @@ namespace operators
{
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value, bool>
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<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>
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<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>
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<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>
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<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>
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<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>
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<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,
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value,
std::basic_ostream<Ch, Tr>&>
operator<<( std::basic_ostream<Ch, Tr>& os, T const& t )
{

View File

@@ -66,6 +66,9 @@ run descriptor_by_pointer_test.cpp ;
compile unnamed_namespace_test.cpp ;
compile unnamed_namespace_test2.cpp ;
run union_test.cpp ;
run union_test2.cpp ;
# examples
obj describe_cxx14 : describe_cxx14.cpp ;

79
test/union_test.cpp Normal file
View File

@@ -0,0 +1,79 @@
// 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>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#elif defined(__GNUC__) && __GNUC__ < 5
BOOST_PRAGMA_MESSAGE("Skipping test because g++ 4.8")
int main() {}
#else
union 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)
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)
#endif // !defined(BOOST_DESCRIBE_CXX11)

153
test/union_test2.cpp Normal file
View File

@@ -0,0 +1,153 @@
// 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>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#elif defined(__GNUC__) && __GNUC__ < 5
BOOST_PRAGMA_MESSAGE("Skipping test because g++ 4.8")
int main() {}
#else
union A
{
public:
int m1;
static int m2;
int f1() const { return m1; }
static int f2() { return m2; }
protected:
int m3;
static int m4;
int f3() const { return m3; }
static int f4() { return m4; }
private:
int m5;
static int m6;
int f5() const { return m5; }
static int f6() { return m6; }
BOOST_DESCRIBE_CLASS(A, (), (m1, m2, f1, f2), (m3, m4, f3, f4), (m5, m6, f5, f6))
friend int main();
};
int A::m2;
int A::m4;
int A::m6;
#if !defined(BOOST_DESCRIBE_CXX14)
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_public | 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 );
}
{
using L = describe_members<A, mod_protected | 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::m3 );
BOOST_TEST_CSTR_EQ( D1::name, "m3" );
BOOST_TEST_EQ( D1::modifiers, mod_protected );
BOOST_TEST( D2::pointer == &A::m4 );
BOOST_TEST_CSTR_EQ( D2::name, "m4" );
BOOST_TEST_EQ( D2::modifiers, mod_protected | mod_static );
BOOST_TEST( D3::pointer == &A::f3 );
BOOST_TEST_CSTR_EQ( D3::name, "f3" );
BOOST_TEST_EQ( D3::modifiers, mod_protected | mod_function );
BOOST_TEST( D4::pointer == &A::f4 );
BOOST_TEST_CSTR_EQ( D4::name, "f4" );
BOOST_TEST_EQ( D4::modifiers, mod_protected | mod_static | mod_function );
}
{
using L = describe_members<A, mod_private | 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::m5 );
BOOST_TEST_CSTR_EQ( D1::name, "m5" );
BOOST_TEST_EQ( D1::modifiers, mod_private );
BOOST_TEST( D2::pointer == &A::m6 );
BOOST_TEST_CSTR_EQ( D2::name, "m6" );
BOOST_TEST_EQ( D2::modifiers, mod_private | mod_static );
BOOST_TEST( D3::pointer == &A::f5 );
BOOST_TEST_CSTR_EQ( D3::name, "f5" );
BOOST_TEST_EQ( D3::modifiers, mod_private | mod_function );
BOOST_TEST( D4::pointer == &A::f6 );
BOOST_TEST_CSTR_EQ( D4::name, "f6" );
BOOST_TEST_EQ( D4::modifiers, mod_private | mod_static | mod_function );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)
#endif // !defined(BOOST_DESCRIBE_CXX11)