1 // Copyright Cromwell D. Enage 2018.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <boost/parameter/config.hpp>
7
8 #if !defined(BOOST_PARAMETER_HAS_PERFECT_FORWARDING) && \
9 (BOOST_PARAMETER_COMPOSE_MAX_ARITY < 3)
10 #error Define BOOST_PARAMETER_COMPOSE_MAX_ARITY as 3 or greater.
11 #endif
12
13 #include <boost/parameter/name.hpp>
14
15 namespace test {
16
17 BOOST_PARAMETER_NAME(a0)
18 BOOST_PARAMETER_NAME(a1)
19 BOOST_PARAMETER_NAME(a2)
20 }
21
22 #if !defined(BOOST_NO_SFINAE)
23 #include <boost/parameter/is_argument_pack.hpp>
24 #include <boost/type_traits/is_convertible.hpp>
25 #include <boost/core/enable_if.hpp>
26 #endif
27
28 namespace test {
29
30 #if !defined(BOOST_NO_SFINAE)
31 struct _enabler
32 {
33 };
34 #endif
35
36 template <typename T>
37 class backend0
38 {
39 T _a0;
40
41 public:
42 template <typename ArgPack>
backend0(ArgPack const & args,typename boost::enable_if<boost::parameter::is_argument_pack<ArgPack>,test::_enabler>::type=test::_enabler ())43 explicit backend0(
44 ArgPack const& args
45 #if !defined(BOOST_NO_SFINAE)
46 , typename boost::enable_if<
47 boost::parameter::is_argument_pack<ArgPack>
48 , test::_enabler
49 >::type = test::_enabler()
50 #endif
51 ) : _a0(args[test::_a0])
52 {
53 }
54
55 #if !defined(BOOST_NO_SFINAE)
56 template <typename U>
backend0(backend0<U> const & copy,typename boost::enable_if<boost::is_convertible<U,T>,test::_enabler>::type=test::_enabler ())57 backend0(
58 backend0<U> const& copy
59 , typename boost::enable_if<
60 boost::is_convertible<U,T>
61 , test::_enabler
62 >::type = test::_enabler()
63 ) : _a0(copy.get_a0())
64 {
65 }
66 #endif
67
68 template <typename Iterator>
backend0(Iterator itr,Iterator itr_end)69 backend0(Iterator itr, Iterator itr_end) : _a0(itr, itr_end)
70 {
71 }
72
get_a0() const73 T const& get_a0() const
74 {
75 return this->_a0;
76 }
77
78 protected:
79 template <typename ArgPack>
initialize_impl(ArgPack const & args)80 void initialize_impl(ArgPack const& args)
81 {
82 this->_a0 = args[test::_a0];
83 }
84 };
85
86 template <typename B, typename T>
87 class backend1 : public B
88 {
89 T _a1;
90
91 public:
92 template <typename ArgPack>
backend1(ArgPack const & args,typename boost::enable_if<boost::parameter::is_argument_pack<ArgPack>,test::_enabler>::type=test::_enabler ())93 explicit backend1(
94 ArgPack const& args
95 #if !defined(BOOST_NO_SFINAE)
96 , typename boost::enable_if<
97 boost::parameter::is_argument_pack<ArgPack>
98 , test::_enabler
99 >::type = test::_enabler()
100 #endif
101 ) : B(args), _a1(args[test::_a1])
102 {
103 }
104
105 #if !defined(BOOST_NO_SFINAE)
106 template <typename Derived>
backend1(Derived const & copy,typename boost::disable_if<boost::parameter::is_argument_pack<Derived>,test::_enabler>::type=test::_enabler ())107 backend1(
108 Derived const& copy
109 , typename boost::disable_if<
110 boost::parameter::is_argument_pack<Derived>
111 , test::_enabler
112 >::type = test::_enabler()
113 ) : B(copy), _a1(copy.get_a1())
114 {
115 }
116 #endif
117
get_a1() const118 T const& get_a1() const
119 {
120 return this->_a1;
121 }
122
123 protected:
124 template <typename ArgPack>
initialize_impl(ArgPack const & args)125 void initialize_impl(ArgPack const& args)
126 {
127 B::initialize_impl(args);
128 this->_a1 = args[test::_a1];
129 }
130 };
131
132 template <typename B, typename T>
133 class backend2 : public B
134 {
135 T _a2;
136
137 public:
138 template <typename ArgPack>
backend2(ArgPack const & args,typename boost::enable_if<boost::parameter::is_argument_pack<ArgPack>,test::_enabler>::type=test::_enabler ())139 explicit backend2(
140 ArgPack const& args
141 #if !defined(BOOST_NO_SFINAE)
142 , typename boost::enable_if<
143 boost::parameter::is_argument_pack<ArgPack>
144 , test::_enabler
145 >::type = test::_enabler()
146 #endif
147 ) : B(args), _a2(args[test::_a2])
148 {
149 }
150
151 #if !defined(BOOST_NO_SFINAE)
152 template <typename Derived>
backend2(Derived const & copy,typename boost::disable_if<boost::parameter::is_argument_pack<Derived>,test::_enabler>::type=test::_enabler ())153 backend2(
154 Derived const& copy
155 , typename boost::disable_if<
156 boost::parameter::is_argument_pack<Derived>
157 , test::_enabler
158 >::type = test::_enabler()
159 ) : B(copy), _a2(copy.get_a2())
160 {
161 }
162 #endif
163
get_a2() const164 T const& get_a2() const
165 {
166 return this->_a2;
167 }
168
169 protected:
170 template <typename ArgPack>
initialize_impl(ArgPack const & args)171 void initialize_impl(ArgPack const& args)
172 {
173 B::initialize_impl(args);
174 this->_a2 = args[test::_a2];
175 }
176 };
177 }
178
179 #include <boost/parameter/preprocessor_no_spec.hpp>
180
181 #if !defined(BOOST_NO_SFINAE)
182 #include <boost/parameter/are_tagged_arguments.hpp>
183 #endif
184
185 namespace test {
186
187 template <typename B>
188 struct frontend : public B
189 {
190 BOOST_PARAMETER_NO_SPEC_CONSTRUCTOR(frontend, (B))
191
192 #if !defined(BOOST_NO_SFINAE)
193 template <typename Iterator>
frontendtest::frontend194 frontend(
195 Iterator itr
196 , Iterator itr_end
197 , typename boost::disable_if<
198 boost::parameter::are_tagged_arguments<Iterator>
199 , test::_enabler
200 >::type = test::_enabler()
201 ) : B(itr, itr_end)
202 {
203 }
204
205 template <typename O>
frontendtest::frontend206 frontend(frontend<O> const& copy) : B(copy)
207 {
208 }
209 #endif
210
211 BOOST_PARAMETER_NO_SPEC_MEMBER_FUNCTION((void), initialize)
212 {
213 this->initialize_impl(args);
214 }
215
216 BOOST_PARAMETER_NO_SPEC_FUNCTION_CALL_OPERATOR((void))
217 {
218 this->initialize_impl(args);
219 }
220 };
221 } // namespace test
222
223 #include <boost/core/lightweight_test.hpp>
224
225 #if !defined(BOOST_NO_SFINAE)
226 #include <string>
227 #endif
228
main()229 int main()
230 {
231 char const* p = "foo";
232 char const* q = "bar";
233 test::frontend<
234 test::backend2<test::backend1<test::backend0<char const*>, char>, int>
235 > composed_obj0(test::_a2 = 4, test::_a1 = ' ', test::_a0 = p);
236 #if defined(BOOST_NO_SFINAE)
237 test::frontend<
238 test::backend1<test::backend2<test::backend0<char const*>, int>, char>
239 > composed_obj1(test::_a0 = p, test::_a1 = ' ', test::_a2 = 4);
240 #else
241 test::frontend<
242 test::backend1<test::backend2<test::backend0<char const*>, int>, char>
243 > composed_obj1(composed_obj0);
244 #endif
245 BOOST_TEST_EQ(composed_obj0.get_a0(), composed_obj1.get_a0());
246 BOOST_TEST_EQ(composed_obj0.get_a1(), composed_obj1.get_a1());
247 BOOST_TEST_EQ(composed_obj0.get_a2(), composed_obj1.get_a2());
248 composed_obj0.initialize(test::_a0 = q, test::_a1 = '!', test::_a2 = 8);
249 composed_obj1.initialize(test::_a2 = 8, test::_a1 = '!', test::_a0 = q);
250 BOOST_TEST_EQ(composed_obj0.get_a0(), composed_obj1.get_a0());
251 BOOST_TEST_EQ(composed_obj0.get_a1(), composed_obj1.get_a1());
252 BOOST_TEST_EQ(composed_obj0.get_a2(), composed_obj1.get_a2());
253 composed_obj0(test::_a2 = 8, test::_a1 = '!', test::_a0 = q);
254 composed_obj1(test::_a0 = q, test::_a1 = '!', test::_a2 = 8);
255 BOOST_TEST_EQ(composed_obj0.get_a0(), composed_obj1.get_a0());
256 BOOST_TEST_EQ(composed_obj0.get_a1(), composed_obj1.get_a1());
257 BOOST_TEST_EQ(composed_obj0.get_a2(), composed_obj1.get_a2());
258 #if !defined(BOOST_NO_SFINAE)
259 test::frontend<test::backend0<std::string> > string_wrap(p, p + 3);
260 BOOST_TEST_EQ(string_wrap.get_a0(), std::string(p));
261 #endif
262 return boost::report_errors();
263 }
264
265