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