Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added constructor descriptors. #34

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions doc/describe/classes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,55 @@ public:

The case where a member function and a static member function have the same name
and the same function type is currently not supported.

## Constructors

Constructors can be described with either `BOOST_DESCRIBE_CLASS_CONSTRUCTORS` for classes with
private members inside the class decleration
or `BOOST_DESCRIBE_STRUCT_CONSTRUCTORS` for a public description from outside the class.

```cpp
class Y
{
private:
Y();
Y(int);

BOOST_DESCRIBE_CLASS_CONSTRUCTORS(Y, (), (int));
};
```

```cpp
struct X
{
X();
X(const double& );
};

BOOST_DESCRIBE_STRUCT_CONSTRUCTORS(X, (), (const double &));
```


The constructor list can be obtained with `describe_constructors<X>`, where `X` is the class.

The entries in the list look like the following:

```cpp
struct C1
{
// The signature of the constructors
using signature = Y(int);

static constexpr unsigned modifiers = mod_constructor;

static constexpr bool is_noexcept = false;
static constexpr bool is_trivial = false;

constexpr static C* construct_at(C* p, int i)
{
return new (p) C(i);
}
};
```

The constructor descriptors do not provide a way to determine visibility.
1 change: 1 addition & 0 deletions include/boost/describe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <boost/describe/enumerators.hpp>
#include <boost/describe/bases.hpp>
#include <boost/describe/constructor.hpp>
#include <boost/describe/members.hpp>
#include <boost/describe/enum.hpp>
#include <boost/describe/class.hpp>
Expand Down
13 changes: 13 additions & 0 deletions include/boost/describe/class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
#define BOOST_DESCRIBE_CLASS(C, Bases, Public, Protected, Private)
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members)

#define BOOST_DESCRIBE_CLASS_CONSTRUCTORS(C, ...)
#define BOOST_DESCRIBE_STRUCT_CONSTRUCTORS(C, ...)

#else

#include <boost/describe/detail/bases.hpp>
#include <boost/describe/detail/constructor.hpp>
#include <boost/describe/detail/members.hpp>
#include <type_traits>

Expand Down Expand Up @@ -59,15 +63,24 @@ namespace describe
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PROTECTED_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Protected) \
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PRIVATE_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Private)

#define BOOST_DESCRIBE_CLASS_CONSTRUCTORS(C, ...) \
template<typename S> friend struct ::boost::describe::detail::ctor_descriptor; \
friend BOOST_DESCRIBE_CTORS(C, __VA_ARGS__)

#define BOOST_DESCRIBE_STRUCT(C, Bases, Members) \
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) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PRIVATE_MEMBERS_(C)

#define BOOST_DESCRIBE_STRUCT_CONSTRUCTORS(C, ...) \
BOOST_DESCRIBE_CTORS(C, __VA_ARGS__)

#endif



} // namespace describe
} // namespace boost

Expand Down
49 changes: 49 additions & 0 deletions include/boost/describe/constructor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright (c) 2022 Klemens Morgenstern ([email protected])
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_DESCRIBE_CONSTRUCTOR_HPP_INCLUDED
#define BOOST_DESCRIBE_CONSTRUCTOR_HPP_INCLUDED

#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
{
namespace describe
{
namespace detail
{

template<class T> using _describe_ctors = decltype( boost_ctor_descriptor_fn( static_cast<T**>(0) ) );

template<class T, class En = void> struct has_describe_ctors: std::false_type
{
};

template<class T> struct has_describe_ctors<T, void_t<_describe_ctors<T>>>: std::true_type
{
};

}

template<class T> using describe_constructors = detail::_describe_ctors<T>;

template<class T> using has_describe_constructors = detail::has_describe_ctors<T>;

}
}

#endif // !defined(BOOST_DESCRIBE_CXX11)

#endif //BOOST_DESCRIBE_CONSTRUCTOR_HPP_INCLUDED
62 changes: 62 additions & 0 deletions include/boost/describe/detail/constructor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// Copyright (c) 2022 Klemens Morgenstern ([email protected])
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_DESCRIBE_DETAIL_CONSTRUCTOR_HPP_INCLUDED
#define BOOST_DESCRIBE_DETAIL_CONSTRUCTOR_HPP_INCLUDED

#include <boost/describe/modifiers.hpp>
#include <type_traits>

namespace boost
{
namespace describe
{
namespace detail
{

template<class S>
struct ctor_descriptor;

template<class C, class ... Args>
struct ctor_descriptor<C(Args...)>
{
using signature = C(Args...);
static constexpr unsigned modifiers = mod_constructor;
static constexpr bool is_noexcept = std::is_nothrow_constructible<C, Args...>::value;
static constexpr bool is_trivial = std::is_trivially_constructible<C, Args...>::value;

constexpr static C* construct_at(C* p, Args... args)
{
return new (p) C(static_cast<Args>(args)...);
}
};

template<class... T> auto ctor_descriptor_fn_impl( int, T... )
{
return list<T...>();
}

#define BOOST_DESCRIBE_CTOR_IMPL(C, B) , boost::describe::detail::ctor_descriptor<C B>()


#if defined(_MSC_VER) && !defined(__clang__)

#define BOOST_DESCRIBE_CTORS(C, ...) inline auto boost_ctor_descriptor_fn( C** ) \
{ return boost::describe::detail::ctor_descriptor_fn_impl( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_CTOR_IMPL, C, __VA_ARGS__) ); }

#else

#define BOOST_DESCRIBE_CTORS(C, ...) inline auto boost_ctor_descriptor_fn( C** ) \
{ return boost::describe::detail::ctor_descriptor_fn_impl( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_CTOR_IMPL, C, ##__VA_ARGS__) ); }

#endif

}
}
}

#endif //BOOST_DESCRIBE_DETAIL_CONSTRUCTOR_HPP_INCLUDED
6 changes: 5 additions & 1 deletion include/boost/describe/detail/members.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ template<unsigned M, class... T> auto member_descriptor_fn_impl( int, T... )
template<class C, class F> constexpr auto mfn( F C::* p ) { return p; }
template<class C, class F> constexpr auto mfn( F * p ) { return p; }

#define BOOST_DESCRIBE_MEMBER_IMPL(C, m) , []{ struct _boost_desc { \
#define BOOST_DESCRIBE_MEMBER_IMPL_(C, m) , []{ struct _boost_desc { \
static constexpr auto pointer() noexcept { return BOOST_DESCRIBE_PP_POINTER(C, m); } \
static constexpr auto name() noexcept { return BOOST_DESCRIBE_PP_NAME(m); } }; return _boost_desc(); }()


#define BOOST_DESCRIBE_MEMBER_IMPL(C, m) \
BOOST_DESCRIBE_MEMBER_IMPL_(C, m)

#if defined(_MSC_VER) && !defined(__clang__)

#define BOOST_DESCRIBE_PUBLIC_MEMBERS(C, ...) inline auto boost_public_member_descriptor_fn( C** ) \
Expand Down
3 changes: 2 additions & 1 deletion include/boost/describe/modifiers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ enum modifiers
mod_function = 32,
mod_any_member = 64,
mod_inherited = 128,
mod_hidden = 256
mod_hidden = 256,
mod_constructor = 512
};

BOOST_DESCRIBE_CONSTEXPR_OR_CONST modifiers mod_any_access = static_cast<modifiers>( mod_public | mod_protected | mod_private );
Expand Down
2 changes: 2 additions & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ run pedantic_members_test.cpp

run enum_from_string_test2.cpp ;

run constructor_test.cpp ;

# examples

obj describe_cxx14 : describe_cxx14.cpp ;
Expand Down
88 changes: 88 additions & 0 deletions test/constructor_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2020 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/constructor.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#include <utility>

class X
{
private:

std::pair<int, int> p_;


X() : p_(0,0) {}
public:
X(int x, int y) noexcept : p_(x, y) {}
X(const std::pair<int, int> & p) : p_(p) {}
BOOST_DESCRIBE_CLASS(X, (), (), (), (p_));
BOOST_DESCRIBE_CLASS_CONSTRUCTORS(X, (), (int, int), (const std::pair<int, int>&));

int x() {return p_.first; }
int y() {return p_.second; }
};


#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;

{

X x(1, 2);
BOOST_TEST_EQ(x.x(), 1);
BOOST_TEST_EQ(x.y(), 2);
using L1 = describe_constructors<X>;

BOOST_TEST_EQ( mp_size<L1>::value, 3 );

using C1 = mp_at_c<L1, 0>;
BOOST_TEST( (std::is_same<C1::signature, X() >::value) );
BOOST_TEST_EQ( C1::modifiers, mod_constructor );
BOOST_TEST_EQ( C1::is_noexcept, false );
BOOST_TEST_EQ( C1::is_trivial, false );
BOOST_TEST_EQ(&x, C1::construct_at(&x));
BOOST_TEST_EQ(x.x(), 0);
BOOST_TEST_EQ(x.y(), 0);

using C2 = mp_at_c<L1, 1>;
BOOST_TEST( (std::is_same<C2::signature, X(int, int) >::value) );
BOOST_TEST_EQ( C2::modifiers, mod_constructor );
BOOST_TEST_EQ( C2::is_noexcept, true );
BOOST_TEST_EQ( C2::is_trivial, false );
BOOST_TEST_EQ(&x, C2::construct_at(&x, 3, 4));
BOOST_TEST_EQ(x.x(), 3);
BOOST_TEST_EQ(x.y(), 4);

using C3 = mp_at_c<L1, 2>;
BOOST_TEST( (std::is_same<C3::signature, X(const std::pair<int, int> &) >::value) );
BOOST_TEST_EQ( C3::modifiers, mod_constructor );
BOOST_TEST_EQ( C3::is_noexcept, false );
BOOST_TEST_EQ( C3::is_trivial, false );
BOOST_TEST_EQ(&x, C3::construct_at(&x, {5,6}));
BOOST_TEST_EQ(x.x(), 5);
BOOST_TEST_EQ(x.y(), 6);

}

return boost::report_errors();
}

#endif // !defined(BOOST_DESCRIBE_CXX14)
Loading