1 // Copyright Daniel Wallin 2006.
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 #include <boost/parameter/preprocessor.hpp>
8 #include <boost/parameter/name.hpp>
9 #include <boost/tuple/tuple.hpp>
10 #include <map>
11 #include <string>
12 #include "basics.hpp"
13 
14 #if defined(BOOST_PARAMETER_CAN_USE_MP11)
15 #include <boost/parameter/value_type.hpp>
16 #include <boost/mp11/map.hpp>
17 #include <boost/core/enable_if.hpp>
18 #include <type_traits>
19 #else
20 #include <boost/mpl/bool.hpp>
21 #include <boost/mpl/if.hpp>
22 #include <boost/type_traits/is_convertible.hpp>
23 #if !defined(BOOST_NO_SFINAE)
24 #include <boost/parameter/value_type.hpp>
25 #include <boost/mpl/has_key.hpp>
26 #include <boost/core/enable_if.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #endif
29 #endif
30 
31 namespace test {
32 
33     BOOST_PARAMETER_NAME(expected)
34     BOOST_PARAMETER_NAME(x)
35     BOOST_PARAMETER_NAME(y)
36     BOOST_PARAMETER_NAME(z)
37 
38 #if defined(BOOST_PARAMETER_CAN_USE_MP11)
39     template <typename To>
40     struct predicate
41     {
42         template <typename From, typename Args>
43         using fn = std::is_convertible<From,To>;
44     };
45 
46     BOOST_PARAMETER_FUNCTION((int), f, test::tag,
47         (required
48             (expected, *)
49         )
50         (deduced
51             (required
52                 (x, *(test::predicate<int>))
53                 (y, *(test::predicate<std::string>))
54             )
55         )
56     )
57 #else   // !defined(BOOST_PARAMETER_CAN_USE_MP11)
58     struct predicate_int
59     {
60         template <typename From, typename Args>
61         struct apply
62           : boost::mpl::if_<
63                 boost::is_convertible<From,int>
64               , boost::mpl::true_
65               , boost::mpl::false_
66             >
67         {
68         };
69     };
70 
71     struct predicate_string
72     {
73         template <typename From, typename Args>
74         struct apply
75           : boost::mpl::if_<
76                 boost::is_convertible<From,std::string>
77               , boost::mpl::true_
78               , boost::mpl::false_
79             >
80         {
81         };
82     };
83 
84     BOOST_PARAMETER_FUNCTION((int), f, test::tag,
85         (required
86             (expected, *)
87         )
88         (deduced
89             (required
90                 (x, *(test::predicate_int))
91                 (y, *(test::predicate_string))
92             )
93         )
94     )
95 #endif  // BOOST_PARAMETER_CAN_USE_MP11
96     {
97         BOOST_TEST(test::equal(x, boost::tuples::get<0>(expected)));
98         BOOST_TEST(test::equal(y, boost::tuples::get<1>(expected)));
99         return 1;
100     }
101 
102     struct X
103     {
Xtest::X104         X(int x_ = -1) : x(x_)
105         {
106         }
107 
operator ==test::X108         bool operator==(X const& other) const
109         {
110             return this->x == other.x;
111         }
112 
113         int x;
114     };
115 
116 #if defined(BOOST_PARAMETER_CAN_USE_MP11)
117     BOOST_PARAMETER_FUNCTION((int), g, test::tag,
118         (required
119             (expected, *)
120         )
121         (deduced
122             (required
123                 (x, *(test::predicate<int>))
124                 (y, *(test::predicate<std::string>))
125             )
126             (optional
127                 (z, *(test::predicate<test::X>), test::X())
128             )
129         )
130     )
131 #else   // !defined(BOOST_PARAMETER_CAN_USE_MP11)
132     struct predicate_X
133     {
134         template <typename From, typename Args>
135         struct apply
136           : boost::mpl::if_<
137                 boost::is_convertible<From,test::X>
138               , boost::mpl::true_
139               , boost::mpl::false_
140             >
141         {
142         };
143     };
144 
145     BOOST_PARAMETER_FUNCTION((int), g, tag,
146         (required
147             (expected, *)
148         )
149         (deduced
150             (required
151                 (x, *(test::predicate_int))
152                 (y, *(test::predicate_string))
153             )
154             (optional
155                 (z, *(test::predicate_X), test::X())
156             )
157         )
158     )
159 #endif  // BOOST_PARAMETER_CAN_USE_MP11
160     {
161         BOOST_TEST(test::equal(x, boost::tuples::get<0>(expected)));
162         BOOST_TEST(test::equal(y, boost::tuples::get<1>(expected)));
163         BOOST_TEST(test::equal(z, boost::tuples::get<2>(expected)));
164         return 1;
165     }
166 
167 #if defined(BOOST_PARAMETER_CAN_USE_MP11)
168     BOOST_PARAMETER_FUNCTION((int), sfinae, test::tag,
169         (deduced
170             (required
171                 (x, *(test::predicate<std::string>))
172             )
173         )
174     )
175 #else
176     BOOST_PARAMETER_FUNCTION((int), sfinae, test::tag,
177         (deduced
178             (required
179                 (x, *(test::predicate_string))
180             )
181         )
182     )
183 #endif
184     {
185         return 1;
186     }
187 
188 #if !defined(BOOST_NO_SFINAE)
189     // On compilers that actually support SFINAE, add another overload
190     // that is an equally good match and can only be in the overload set
191     // when the others are not.  This tests that the SFINAE is actually
192     // working.  On all other compilers we're just checking that everything
193     // about SFINAE-enabled code will work, except of course the SFINAE.
194     template <typename A0>
195     typename boost::enable_if<
196 #if defined(BOOST_PARAMETER_CAN_USE_MP11)
197         std::is_same<int,A0>
198 #else
199         typename boost::mpl::if_<
200             boost::is_same<int,A0>
201           , boost::mpl::true_
202           , boost::mpl::false_
203         >::type
204 #endif
205       , int
206     >::type
sfinae(A0 const & a0)207         sfinae(A0 const& a0)
208     {
209         return 0;
210     }
211 
212 #if defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE_VENDOR_SPECIFIC) || \
213     !BOOST_WORKAROUND(BOOST_MSVC, < 1800)
214     // Test support for two different Boost.Parameter-enabled
215     // function call operator overloads.
216     class char_read_base
217     {
218         int index;
219         char const* key;
220 
221      public:
222         template <typename Args>
char_read_base(Args const & args)223         explicit char_read_base(Args const& args)
224           : index(args[test::_y]), key(args[test::_z])
225         {
226         }
227 
228         BOOST_PARAMETER_FUNCTION_CALL_OPERATOR((void), test::tag,
229             (deduced
230                 (required
231                     (y, (int))
232                     (z, (char const*))
233                 )
234             )
235         )
236         {
237             this->index = y;
238             this->key = z;
239         }
240 
241         BOOST_PARAMETER_CONST_FUNCTION_CALL_OPERATOR((char), test::tag,
242             (deduced
243                 (required
244                     (y, (bool))
245                     (z, (std::map<char const*,std::string>))
246                 )
247             )
248         )
249         {
250             return y ? (
251                 (z.find(this->key)->second)[this->index]
252             ) : this->key[this->index];
253         }
254     };
255 
256     struct char_reader : public char_read_base
257     {
258         BOOST_PARAMETER_CONSTRUCTOR(char_reader, (char_read_base), test::tag,
259             (deduced
260                 (required
261                     (y, (int))
262                     (z, (char const*))
263                 )
264             )
265         )
266     };
267 #endif  // MSVC-11.0-
268 
269     // Test Boost.Parameter-enabled functions
270     // with parameter-dependent return types.
271 #if !defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE)
272 #if defined(BOOST_PARAMETER_CAN_USE_MP11)
273     BOOST_PARAMETER_FUNCTION(
274         (
275             boost::lazy_enable_if<
276                 boost::mp11::mp_map_contains<Args,test::tag::y>
277               , boost::parameter::value_type<Args,test::tag::y>
278             >
279         ), return_y, test::tag,
280         (deduced
281             (required
282                 (x, (std::map<char const*,std::string>))
283                 (y, (char const*))
284             )
285             (optional
286                 (z, (int), 4)
287             )
288         )
289     )
290 #else   // !defined(BOOST_PARAMETER_CAN_USE_MP11)
291     BOOST_PARAMETER_FUNCTION(
292         (
293             boost::lazy_enable_if<
294                 typename boost::mpl::has_key<Args,test::tag::y>::type
295               , boost::parameter::value_type<Args,test::tag::y>
296             >
297         ), return_y, test::tag,
298         (deduced
299             (required
300                 (x, (std::map<char const*,std::string>))
301                 (y, (char const*))
302             )
303             (optional
304                 (z, (int), 4)
305             )
306         )
307     )
308 #endif  // BOOST_PARAMETER_CAN_USE_MP11
309     {
310         return y;
311     }
312 #endif  // LIBS_PARAMETER_TEST_COMPILE_FAILURE
313 #endif  // BOOST_NO_SFINAE
314 
315 #if defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE)
316     BOOST_PARAMETER_FUNCTION(
317         (typename boost::parameter::value_type<Args,test::tag::y>::type),
318         return_y, test::tag,
319         (deduced
320             (required
321                 (x, (std::map<char const*,std::string>))
322                 (y, (char const*))
323             )
324             (optional
325                 (z, (int), 4)
326             )
327         )
328     )
329     {
330         return y;
331     }
332 #endif  // defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE)
333 } // namespace test
334 
335 #include <boost/core/lightweight_test.hpp>
336 
main()337 int main()
338 {
339     test::f(
340         boost::make_tuple(0, std::string("foo"))
341       , test::_x = 0
342       , test::_y = std::string("foo")
343     );
344     test::f(
345         boost::make_tuple(0, std::string("foo"))
346       , 0
347       , std::string("foo")
348     );
349     test::f(
350         boost::make_tuple(0, std::string("foo"))
351       , std::string("foo")
352       , 0
353     );
354     test::f(
355         boost::make_tuple(0, std::string("foo"))
356       , test::_y = std::string("foo")
357       , 0
358     );
359     test::f(
360         boost::make_tuple(0, std::string("foo"))
361       , test::_x = 0
362       , std::string("foo")
363     );
364     test::f(
365         boost::make_tuple(0, std::string("foo"))
366       , 0
367       , test::_y = std::string("foo")
368     );
369     test::g(
370         boost::make_tuple(0, std::string("foo"), test::X())
371       , test::_x = 0
372       , test::_y = std::string("foo")
373     );
374     test::g(
375         boost::make_tuple(0, std::string("foo"), test::X())
376       , 0
377       , std::string("foo")
378     );
379     test::g(
380         boost::make_tuple(0, std::string("foo"), test::X())
381       , std::string("foo")
382       , 0
383     );
384     test::g(
385         boost::make_tuple(0, std::string("foo"), test::X())
386       , test::_y = std::string("foo")
387       , 0
388     );
389     test::g(
390         boost::make_tuple(0, std::string("foo"), test::X())
391       , test::_x = 0
392       , std::string("foo")
393     );
394     test::g(
395         boost::make_tuple(0, std::string("foo"), test::X())
396       , 0
397       , test::_y = std::string("foo")
398     );
399     test::g(
400         boost::make_tuple(0, std::string("foo"), test::X(1))
401       , 0
402       , test::_y = std::string("foo")
403       , test::X(1)
404     );
405     test::g(
406         boost::make_tuple(0, std::string("foo"), test::X(1))
407       , test::X(1)
408       , 0
409       , test::_y = std::string("foo")
410     );
411 
412     std::map<char const*,std::string> k2s;
413 #if !defined(BOOST_NO_SFINAE)
414     char const* keys[] = {"foo", "bar", "baz"};
415     BOOST_TEST_EQ(1, test::sfinae(keys[0]));
416     BOOST_TEST_EQ(0, test::sfinae(0));
417 #if defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE_VENDOR_SPECIFIC) || \
418     !BOOST_WORKAROUND(BOOST_MSVC, < 1800)
419     k2s[keys[0]] = std::string("qux");
420     k2s[keys[1]] = std::string("wmb");
421     k2s[keys[2]] = std::string("zxc");
422     test::char_reader r(keys[0], 0);
423     BOOST_TEST_EQ('q', (r(k2s, true)));
424     BOOST_TEST_EQ('f', (r(k2s, false)));
425     r(keys[1], 1);
426     BOOST_TEST_EQ('m', (r(k2s, true)));
427     BOOST_TEST_EQ('a', (r(k2s, false)));
428     r(keys[2], 2);
429     BOOST_TEST_EQ('c', (r(k2s, true)));
430     BOOST_TEST_EQ('z', (r(k2s, false)));
431 #endif  // MSVC-11.0-
432 #if !defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE)
433     BOOST_TEST_EQ(keys[1], test::return_y(2, k2s, keys[1]));
434 #endif
435 #endif  // BOOST_NO_SFINAE
436 
437 #if defined(LIBS_PARAMETER_TEST_COMPILE_FAILURE)
438     BOOST_TEST_EQ(keys[1], test::return_y(2, k2s, keys[1]));
439 #endif
440 
441     return boost::report_errors();
442 }
443 
444