Skip to content

Commit 664ed1c

Browse files
Added constructor descriptors.
Closes #27
1 parent 18e7c01 commit 664ed1c

File tree

9 files changed

+274
-2
lines changed

9 files changed

+274
-2
lines changed

doc/describe/classes.adoc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,55 @@ public:
187187

188188
The case where a member function and a static member function have the same name
189189
and the same function type is currently not supported.
190+
191+
## Constructors
192+
193+
Constructors can be described with either `BOOST_DESCRIBE_CLASS_CONSTRUCTORS` for classes with
194+
private members inside the class decleration
195+
or `BOOST_DESCRIBE_STRUCT_CONSTRUCTORS` for a public description from outside the class.
196+
197+
```cpp
198+
class Y
199+
{
200+
private:
201+
Y();
202+
Y(int);
203+
204+
BOOST_DESCRIBE_CLASS_CONSTRUCTORS(Y, (), (int));
205+
};
206+
```
207+
208+
```cpp
209+
struct X
210+
{
211+
X();
212+
X(const double& );
213+
};
214+
215+
BOOST_DESCRIBE_STRUCT_CONSTRUCTORS(X, (), (const double &));
216+
```
217+
218+
219+
The constructor list can be obtained with `describe_constructors<X>`, where `X` is the class.
220+
221+
The entries in the list look like the following:
222+
223+
```cpp
224+
struct C1
225+
{
226+
// The signature of the constructors
227+
using signature = Y(int);
228+
229+
static constexpr unsigned modifiers = mod_constructor;
230+
231+
static constexpr bool is_noexcept = false;
232+
static constexpr bool is_trivial = false;
233+
234+
constexpr static C* construct_at(C* p, int i)
235+
{
236+
return new (p) C(i);
237+
}
238+
};
239+
```
240+
241+
The constructor descriptors do not provide a way to determine visibility.

include/boost/describe.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <boost/describe/enumerators.hpp>
99
#include <boost/describe/bases.hpp>
10+
#include <boost/describe/constructor.hpp>
1011
#include <boost/describe/members.hpp>
1112
#include <boost/describe/enum.hpp>
1213
#include <boost/describe/class.hpp>

include/boost/describe/class.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@
1212
#define BOOST_DESCRIBE_CLASS(C, Bases, Public, Protected, Private)
1313
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members)
1414

15+
#define BOOST_DESCRIBE_CLASS_CONSTRUCTORS(C, ...)
16+
#define BOOST_DESCRIBE_STRUCT_CONSTRUCTORS(C, ...)
17+
1518
#else
1619

1720
#include <boost/describe/detail/bases.hpp>
21+
#include <boost/describe/detail/constructor.hpp>
1822
#include <boost/describe/detail/members.hpp>
1923
#include <type_traits>
2024

@@ -59,15 +63,24 @@ namespace describe
5963
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PROTECTED_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Protected) \
6064
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PRIVATE_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Private)
6165

66+
#define BOOST_DESCRIBE_CLASS_CONSTRUCTORS(C, ...) \
67+
template<typename S> friend struct ::boost::describe::detail::ctor_descriptor; \
68+
friend BOOST_DESCRIBE_CTORS(C, __VA_ARGS__)
69+
6270
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members) \
6371
static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
6472
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_BASES_(C BOOST_DESCRIBE_PP_UNPACK Bases) \
6573
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Members) \
6674
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PROTECTED_MEMBERS_(C) \
6775
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PRIVATE_MEMBERS_(C)
6876

77+
#define BOOST_DESCRIBE_STRUCT_CONSTRUCTORS(C, ...) \
78+
BOOST_DESCRIBE_CTORS(C, __VA_ARGS__)
79+
6980
#endif
7081

82+
83+
7184
} // namespace describe
7285
} // namespace boost
7386

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Copyright (c) 2022 Klemens Morgenstern ([email protected])
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
8+
#ifndef BOOST_DESCRIBE_CONSTRUCTOR_HPP_INCLUDED
9+
#define BOOST_DESCRIBE_CONSTRUCTOR_HPP_INCLUDED
10+
11+
#include <boost/describe/modifiers.hpp>
12+
#include <boost/describe/detail/void_t.hpp>
13+
#include <boost/describe/detail/config.hpp>
14+
15+
16+
#if defined(BOOST_DESCRIBE_CXX11)
17+
18+
#include <boost/mp11/algorithm.hpp>
19+
#include <type_traits>
20+
21+
namespace boost
22+
{
23+
namespace describe
24+
{
25+
namespace detail
26+
{
27+
28+
template<class T> using _describe_ctors = decltype( boost_ctor_descriptor_fn( static_cast<T**>(0) ) );
29+
30+
template<class T, class En = void> struct has_describe_ctors: std::false_type
31+
{
32+
};
33+
34+
template<class T> struct has_describe_ctors<T, void_t<_describe_ctors<T>>>: std::true_type
35+
{
36+
};
37+
38+
}
39+
40+
template<class T> using describe_constructors = detail::_describe_ctors<T>;
41+
42+
template<class T> using has_describe_constructors = detail::has_describe_ctors<T>;
43+
44+
}
45+
}
46+
47+
#endif // !defined(BOOST_DESCRIBE_CXX11)
48+
49+
#endif //BOOST_DESCRIBE_CONSTRUCTOR_HPP_INCLUDED
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Copyright (c) 2022 Klemens Morgenstern ([email protected])
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
8+
#ifndef BOOST_DESCRIBE_DETAIL_CONSTRUCTOR_HPP_INCLUDED
9+
#define BOOST_DESCRIBE_DETAIL_CONSTRUCTOR_HPP_INCLUDED
10+
11+
#include <boost/describe/modifiers.hpp>
12+
#include <type_traits>
13+
14+
namespace boost
15+
{
16+
namespace describe
17+
{
18+
namespace detail
19+
{
20+
21+
template<class S>
22+
struct ctor_descriptor;
23+
24+
template<class C, class ... Args>
25+
struct ctor_descriptor<C(Args...)>
26+
{
27+
using signature = C(Args...);
28+
static constexpr unsigned modifiers = mod_constructor;
29+
static constexpr bool is_noexcept = std::is_nothrow_constructible<C, Args...>::value;
30+
static constexpr bool is_trivial = std::is_trivially_constructible<C, Args...>::value;
31+
32+
constexpr static C* construct_at(C* p, Args... args)
33+
{
34+
return new (p) C(static_cast<Args>(args)...);
35+
}
36+
};
37+
38+
template<class... T> auto ctor_descriptor_fn_impl( int, T... )
39+
{
40+
return list<T...>();
41+
}
42+
43+
#define BOOST_DESCRIBE_CTOR_IMPL(C, B) , boost::describe::detail::ctor_descriptor<C B>()
44+
45+
46+
#if defined(_MSC_VER) && !defined(__clang__)
47+
48+
#define BOOST_DESCRIBE_CTORS(C, ...) inline auto boost_ctor_descriptor_fn( C** ) \
49+
{ return boost::describe::detail::ctor_descriptor_fn_impl( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_CTOR_IMPL, C, __VA_ARGS__) ); }
50+
51+
#else
52+
53+
#define BOOST_DESCRIBE_CTORS(C, ...) inline auto boost_ctor_descriptor_fn( C** ) \
54+
{ return boost::describe::detail::ctor_descriptor_fn_impl( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_CTOR_IMPL, C, ##__VA_ARGS__) ); }
55+
56+
#endif
57+
58+
}
59+
}
60+
}
61+
62+
#endif //BOOST_DESCRIBE_DETAIL_CONSTRUCTOR_HPP_INCLUDED

include/boost/describe/detail/members.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ template<unsigned M, class... T> auto member_descriptor_fn_impl( int, T... )
4949
template<class C, class F> constexpr auto mfn( F C::* p ) { return p; }
5050
template<class C, class F> constexpr auto mfn( F * p ) { return p; }
5151

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

56+
57+
#define BOOST_DESCRIBE_MEMBER_IMPL(C, m) \
58+
BOOST_DESCRIBE_MEMBER_IMPL_(C, m)
59+
5660
#if defined(_MSC_VER) && !defined(__clang__)
5761

5862
#define BOOST_DESCRIBE_PUBLIC_MEMBERS(C, ...) inline auto boost_public_member_descriptor_fn( C** ) \

include/boost/describe/modifiers.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ enum modifiers
2222
mod_function = 32,
2323
mod_any_member = 64,
2424
mod_inherited = 128,
25-
mod_hidden = 256
25+
mod_hidden = 256,
26+
mod_constructor = 512
2627
};
2728

2829
BOOST_DESCRIBE_CONSTEXPR_OR_CONST modifiers mod_any_access = static_cast<modifiers>( mod_public | mod_protected | mod_private );

test/Jamfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ run pedantic_members_test.cpp
8585

8686
run enum_from_string_test2.cpp ;
8787

88+
run constructor_test.cpp ;
89+
8890
# examples
8991

9092
obj describe_cxx14 : describe_cxx14.cpp ;

test/constructor_test.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2020 Peter Dimov
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
5+
#include <boost/describe/members.hpp>
6+
#include <boost/describe/constructor.hpp>
7+
#include <boost/describe/class.hpp>
8+
#include <boost/core/lightweight_test.hpp>
9+
#include <utility>
10+
11+
class X
12+
{
13+
private:
14+
15+
std::pair<int, int> p_;
16+
17+
18+
X() : p_(0,0) {}
19+
public:
20+
X(int x, int y) noexcept : p_(x, y) {}
21+
X(const std::pair<int, int> & p) : p_(p) {}
22+
BOOST_DESCRIBE_CLASS(X, (), (), (), (p_));
23+
BOOST_DESCRIBE_CLASS_CONSTRUCTORS(X, (), (int, int), (const std::pair<int, int>&));
24+
25+
int x() {return p_.first; }
26+
int y() {return p_.second; }
27+
};
28+
29+
30+
#if !defined(BOOST_DESCRIBE_CXX14)
31+
32+
#include <boost/config/pragma_message.hpp>
33+
34+
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
35+
int main() {}
36+
37+
#else
38+
39+
#include <boost/mp11.hpp>
40+
41+
42+
int main()
43+
{
44+
using namespace boost::describe;
45+
using namespace boost::mp11;
46+
47+
{
48+
49+
X x(1, 2);
50+
BOOST_TEST_EQ(x.x(), 1);
51+
BOOST_TEST_EQ(x.y(), 2);
52+
using L1 = describe_constructors<X>;
53+
54+
BOOST_TEST_EQ( mp_size<L1>::value, 3 );
55+
56+
using C1 = mp_at_c<L1, 0>;
57+
BOOST_TEST( (std::is_same<C1::signature, X() >::value) );
58+
BOOST_TEST_EQ( C1::modifiers, mod_constructor );
59+
BOOST_TEST_EQ( C1::is_noexcept, false );
60+
BOOST_TEST_EQ( C1::is_trivial, false );
61+
BOOST_TEST_EQ(&x, C1::construct_at(&x));
62+
BOOST_TEST_EQ(x.x(), 0);
63+
BOOST_TEST_EQ(x.y(), 0);
64+
65+
using C2 = mp_at_c<L1, 1>;
66+
BOOST_TEST( (std::is_same<C2::signature, X(int, int) >::value) );
67+
BOOST_TEST_EQ( C2::modifiers, mod_constructor );
68+
BOOST_TEST_EQ( C2::is_noexcept, true );
69+
BOOST_TEST_EQ( C2::is_trivial, false );
70+
BOOST_TEST_EQ(&x, C2::construct_at(&x, 3, 4));
71+
BOOST_TEST_EQ(x.x(), 3);
72+
BOOST_TEST_EQ(x.y(), 4);
73+
74+
using C3 = mp_at_c<L1, 2>;
75+
BOOST_TEST( (std::is_same<C3::signature, X(const std::pair<int, int> &) >::value) );
76+
BOOST_TEST_EQ( C3::modifiers, mod_constructor );
77+
BOOST_TEST_EQ( C3::is_noexcept, false );
78+
BOOST_TEST_EQ( C3::is_trivial, false );
79+
BOOST_TEST_EQ(&x, C3::construct_at(&x, {5,6}));
80+
BOOST_TEST_EQ(x.x(), 5);
81+
BOOST_TEST_EQ(x.y(), 6);
82+
83+
}
84+
85+
return boost::report_errors();
86+
}
87+
88+
#endif // !defined(BOOST_DESCRIBE_CXX14)

0 commit comments

Comments
 (0)