1 /*=============================================================================
2     Copyright (C) 2016 Lee Clagett
3     Copyright (C) 2018 Kohei Takahashi
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 
9 #include <boost/config.hpp>
10 #include <boost/detail/lightweight_test.hpp>
11 #include <boost/fusion/container/list.hpp>
12 #include <boost/fusion/container/vector.hpp>
13 #include <boost/type_traits/add_const.hpp>
14 #include <boost/type_traits/add_reference.hpp>
15 #include <boost/type_traits/integral_constant.hpp>
16 #include <boost/type_traits/is_constructible.hpp>
17 #include <boost/type_traits/is_convertible.hpp>
18 #include <boost/type_traits/remove_const.hpp>
19 #include <boost/type_traits/remove_reference.hpp>
20 
21 struct convertible
22 {
convertibleconvertible23     convertible(int) {}
24 };
25 
26 template <typename From, typename To>
is_convertible(bool has_conversion)27 bool is_convertible(bool has_conversion)
28 {
29     typedef typename boost::remove_reference<
30         typename boost::remove_const<From>::type
31     >::type from_rvalue;
32     typedef typename boost::add_reference<from_rvalue>::type from_lvalue;
33     typedef typename boost::add_const<from_lvalue>::type from_const_lvalue;
34 
35     return
36         boost::is_convertible<from_rvalue, To>::value == has_conversion &&
37         boost::is_convertible<from_lvalue, To>::value == has_conversion &&
38         boost::is_convertible<from_const_lvalue, To>::value == has_conversion;
39 }
40 
41 // is_constructible has a few requirements
42 #ifdef BOOST_TT_IS_CONSTRUCTIBLE_CONFORMING
43 
44 #define FUSION_TEST_HAS_CONSTRUCTIBLE
45 
46 template <typename To, typename... Args>
is_lvalue_constructible(bool has_constructor)47 bool is_lvalue_constructible(bool has_constructor)
48 {
49     return has_constructor ==
50         boost::is_constructible<
51             To
52           , typename boost::add_reference<Args>::type...
53         >::value;
54 }
55 
56 template <typename To, typename... Args>
is_constructible_impl(bool has_constructor)57 bool is_constructible_impl(bool has_constructor)
58 {
59     return
60         boost::is_constructible<To, Args...>::value == has_constructor &&
61         is_lvalue_constructible<To, Args...>(has_constructor) &&
62         is_lvalue_constructible<
63             To, typename boost::add_const<Args>::type...
64         >(has_constructor);
65 }
66 
67 template <typename To, typename... Args>
is_constructible(bool has_constructor)68 bool is_constructible(bool has_constructor)
69 {
70     return
71         is_constructible_impl<
72             To
73           , typename boost::remove_reference<
74                 typename boost::remove_const<Args>::type
75             >::type...
76         >(has_constructor);
77 }
78 
test_constructible()79 void test_constructible()
80 {
81     BOOST_TEST((is_constructible< FUSION_SEQUENCE<> >(true)));
82 
83     BOOST_TEST((is_constructible< FUSION_SEQUENCE<int> >(true)));
84     BOOST_TEST((is_constructible<FUSION_SEQUENCE<int>, int>(true)));
85 
86     BOOST_TEST((is_constructible<FUSION_SEQUENCE<convertible>, int>(true)));
87     BOOST_TEST((
88         is_constructible<FUSION_SEQUENCE<convertible>, convertible>(true)
89     ));
90 
91     // boost::is_constructible always fail to test ctor which takes 2 or more arguments on GCC 4.7.
92 #if !BOOST_WORKAROUND(BOOST_GCC, < 40700)
93     BOOST_TEST((
94         is_constructible<FUSION_SEQUENCE<int, int>, int, int>(true)
95     ));
96 
97     BOOST_TEST((
98         is_constructible<FUSION_SEQUENCE<convertible, int>, int, int>(true)
99     ));
100     BOOST_TEST((
101         is_constructible<
102             FUSION_SEQUENCE<convertible, int>, convertible, int
103         >(true)
104     ));
105 
106     BOOST_TEST((
107         is_constructible<FUSION_SEQUENCE<int, convertible>, int, int>(true)
108     ));
109     BOOST_TEST((
110         is_constructible<
111             FUSION_SEQUENCE<int, convertible>, int, convertible
112         >(true)
113     ));
114 
115     BOOST_TEST((
116         is_constructible<
117             FUSION_SEQUENCE<convertible, convertible>, int, int
118         >(true)
119     ));
120     BOOST_TEST((
121         is_constructible<
122             FUSION_SEQUENCE<convertible, convertible>, convertible, int
123         >(true)
124     ));
125     BOOST_TEST((
126         is_constructible<
127             FUSION_SEQUENCE<convertible, convertible>, int, convertible
128         >(true)
129     ));
130     BOOST_TEST((
131         is_constructible<
132             FUSION_SEQUENCE<convertible, convertible>, convertible, convertible
133         >(true)
134     ));
135 #endif // !(gcc < 4.7)
136 }
137 
138 #endif // is_constructible is available
139 
test_convertible(bool has_seq_conversion)140 void test_convertible(bool has_seq_conversion)
141 {
142     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<> >(false)));
143     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<int> >(false)));
144     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<const int&> >(false)));
145     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<convertible> >(false)));
146     BOOST_TEST((
147         is_convertible<int, FUSION_SEQUENCE<const convertible&> >(false)
148     ));
149     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<int, int> >(false)));
150     BOOST_TEST((
151         is_convertible<int, FUSION_SEQUENCE<const int&, const int&> >(false)
152     ));
153     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<convertible, int> >(false)));
154     BOOST_TEST((
155         is_convertible<int, FUSION_SEQUENCE<const convertible&, const int&> >(false)
156     ));
157     BOOST_TEST((is_convertible<int, FUSION_SEQUENCE<int, convertible> >(false)));
158     BOOST_TEST((
159         is_convertible<int, FUSION_SEQUENCE<const int&, const convertible&> >(false)
160     ));
161     BOOST_TEST((
162         is_convertible<int, FUSION_SEQUENCE<convertible, convertible> >(false)
163     ));
164     BOOST_TEST((
165         is_convertible<
166             int, FUSION_SEQUENCE<const convertible&, const convertible&>
167         >(false)
168     ));
169 
170     BOOST_TEST((is_convertible<FUSION_SEQUENCE<>, FUSION_SEQUENCE<> >(true)));
171     BOOST_TEST((
172         is_convertible<FUSION_SEQUENCE<int>, FUSION_SEQUENCE<int> >(true)
173     ));
174     BOOST_TEST((
175         is_convertible<FUSION_SEQUENCE<int>, FUSION_SEQUENCE<const int&> >(true)
176     ));
177     BOOST_TEST((
178         is_convertible<FUSION_SEQUENCE<int>, FUSION_SEQUENCE<convertible> >(true)
179     ));
180     BOOST_TEST((
181         is_convertible<FUSION_SEQUENCE<int, int>, FUSION_SEQUENCE<int, int> >(true)
182     ));
183     BOOST_TEST((
184         is_convertible<
185             FUSION_SEQUENCE<int, int>, FUSION_SEQUENCE<const int&, const int&>
186         >(true)
187     ));
188     BOOST_TEST((
189         is_convertible<
190             FUSION_SEQUENCE<int, int>, FUSION_SEQUENCE<convertible, int>
191         >(true)
192     ));
193     BOOST_TEST((
194         is_convertible<
195             FUSION_SEQUENCE<int, int>, FUSION_SEQUENCE<int, convertible>
196         >(true)
197     ));
198     BOOST_TEST((
199         is_convertible<
200             FUSION_SEQUENCE<int, int>
201           , FUSION_SEQUENCE<convertible, convertible>
202         >(true)
203     ));
204 
205     BOOST_TEST((
206         is_convertible<
207             FUSION_ALT_SEQUENCE<>, FUSION_SEQUENCE<>
208         >(has_seq_conversion)
209     ));
210     BOOST_TEST((
211         is_convertible<
212             FUSION_ALT_SEQUENCE<int>, FUSION_SEQUENCE<int>
213         >(has_seq_conversion)
214     ));
215     BOOST_TEST((
216         is_convertible<
217             FUSION_ALT_SEQUENCE<int>, FUSION_SEQUENCE<const int&>
218         >(has_seq_conversion)
219     ));
220     BOOST_TEST((
221         is_convertible<
222             FUSION_ALT_SEQUENCE<int>, FUSION_SEQUENCE<convertible>
223         >(has_seq_conversion)
224     ));
225     BOOST_TEST((
226         is_convertible<
227             FUSION_ALT_SEQUENCE<int, int>, FUSION_SEQUENCE<int, int>
228         >(has_seq_conversion)
229     ));
230     BOOST_TEST((
231         is_convertible<
232             FUSION_ALT_SEQUENCE<int, int>
233           , FUSION_SEQUENCE<const int&, const int&>
234         >(has_seq_conversion)
235     ));
236     BOOST_TEST((
237         is_convertible<
238             FUSION_ALT_SEQUENCE<int, int>, FUSION_SEQUENCE<convertible, int>
239         >(has_seq_conversion)
240     ));
241     BOOST_TEST((
242         is_convertible<
243             FUSION_ALT_SEQUENCE<int, int>, FUSION_SEQUENCE<int, convertible>
244         >(has_seq_conversion)
245     ));
246     BOOST_TEST((
247         is_convertible<
248             FUSION_ALT_SEQUENCE<int, int>
249           , FUSION_SEQUENCE<convertible, convertible>
250         >(has_seq_conversion)
251     ));
252 }
253 
254