1 // Copyright Louis Dionne 2013-2017
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
4 
5 #include <boost/hana/assert.hpp>
6 #include <boost/hana/bool.hpp>
7 #include <boost/hana/equal.hpp>
8 #include <boost/hana/fwd/hash.hpp>
9 #include <boost/hana/map.hpp>
10 #include <boost/hana/pair.hpp>
11 #include <boost/hana/type.hpp>
12 
13 #include <support/constexpr_move_only.hpp>
14 #include <support/tracked_move_only.hpp>
15 
16 #include <string>
17 #include <type_traits>
18 #include <utility>
19 namespace hana = boost::hana;
20 
21 
in_constexpr_context()22 constexpr bool in_constexpr_context() {
23     auto t0 = hana::make_map(
24         hana::make_pair(ConstexprMoveOnly<2>{}, ConstexprMoveOnly<20>{}),
25         hana::make_pair(ConstexprMoveOnly<3>{}, ConstexprMoveOnly<30>{}));
26     auto t_implicit = std::move(t0);
27     auto t_explicit(std::move(t_implicit));
28 
29     (void)t_implicit;
30     (void)t_explicit;
31     return true;
32 }
33 
34 static_assert(in_constexpr_context(), "");
35 
36 
37 struct NoMove {
38     NoMove() = default;
39     NoMove(NoMove const&) = delete;
40     NoMove(NoMove&&) = delete;
operator ==(NoMove const &,NoMove const &)41     friend auto operator==(NoMove const&, NoMove const&) { return hana::true_c; }
operator !=(NoMove const &,NoMove const &)42     friend auto operator!=(NoMove const&, NoMove const&) { return hana::false_c; }
43 };
44 
45 // Note: It is also useful to check with a non-empty class, because that
46 //       triggers different instantiations due to EBO.
47 struct NoMove_nonempty {
48     NoMove_nonempty() = default;
49     NoMove_nonempty(NoMove_nonempty const&) = delete;
50     NoMove_nonempty(NoMove_nonempty&&) = delete;
51     int i;
operator ==(NoMove_nonempty const &,NoMove_nonempty const &)52     friend auto operator==(NoMove_nonempty const&, NoMove_nonempty const&) { return hana::true_c; }
operator !=(NoMove_nonempty const &,NoMove_nonempty const &)53     friend auto operator!=(NoMove_nonempty const&, NoMove_nonempty const&) { return hana::false_c; }
54 };
55 
56 namespace boost { namespace hana {
57     template <>
58     struct hash_impl<NoMove> {
applyboost::hana::hash_impl59         static constexpr auto apply(NoMove const&)
60         { return hana::type_c<NoMove>; };
61     };
62 
63     template <>
64     struct hash_impl<NoMove_nonempty> {
applyboost::hana::hash_impl65         static constexpr auto apply(NoMove_nonempty const&)
66         { return hana::type_c<NoMove_nonempty>; };
67     };
68 }}
69 
main()70 int main() {
71     {
72         auto t0 = hana::make_map();
73         auto t_implicit = std::move(t0);
74         auto t_explicit(std::move(t_implicit));
75 
76         (void)t_explicit;
77         (void)t_implicit;
78     }
79     {
80         auto t0 = hana::make_map(hana::make_pair(TrackedMoveOnly<1>{}, TrackedMoveOnly<10>{}));
81         auto t_implicit = std::move(t0);
82         auto t_explicit(std::move(t_implicit));
83 
84         (void)t_implicit;
85         (void)t_explicit;
86     }
87     {
88         auto t0 = hana::make_map(hana::make_pair(TrackedMoveOnly<1>{}, TrackedMoveOnly<10>{}),
89                                  hana::make_pair(TrackedMoveOnly<2>{}, TrackedMoveOnly<20>{}));
90         auto t_implicit = std::move(t0);
91         auto t_explicit(std::move(t_implicit));
92 
93         (void)t_implicit;
94         (void)t_explicit;
95     }
96     {
97         auto t0 = hana::make_map(hana::make_pair(TrackedMoveOnly<1>{}, TrackedMoveOnly<10>{}),
98                                  hana::make_pair(TrackedMoveOnly<2>{}, TrackedMoveOnly<20>{}),
99                                  hana::make_pair(TrackedMoveOnly<3>{}, TrackedMoveOnly<30>{}));
100         auto t_implicit = std::move(t0);
101         auto t_explicit(std::move(t_implicit));
102 
103         (void)t_implicit;
104         (void)t_explicit;
105     }
106     {
107         auto t0 = hana::make_map(hana::make_pair(hana::int_c<2>, std::string{"abcdef"}));
108         auto moved = std::move(t0);
109         BOOST_HANA_RUNTIME_CHECK(
110             moved == hana::make_map(hana::make_pair(hana::int_c<2>, std::string{"abcdef"}))
111         );
112     }
113 
114     {
115         using Map1 = hana::map<hana::pair<NoMove, NoMove>>;
116         Map1 map1; (void)map1;
117         static_assert(!std::is_move_constructible<Map1>::value, "");
118 
119         using Map2 = hana::map<hana::pair<NoMove_nonempty, NoMove_nonempty>>;
120         Map2 map2; (void)map2;
121         static_assert(!std::is_move_constructible<Map2>::value, "");
122     }
123 }
124