1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // <tuple> |
10 | |
11 | // template <class... Types> class tuple; |
12 | |
13 | // tuple(tuple&& u); |
14 | |
15 | // UNSUPPORTED: c++03 |
16 | |
17 | #include <tuple> |
18 | #include <utility> |
19 | #include <cassert> |
20 | #include <memory> |
21 | |
22 | #include "test_macros.h" |
23 | #include "MoveOnly.h" |
24 | |
25 | struct ConstructsWithTupleLeaf |
26 | { |
27 | ConstructsWithTupleLeaf() {} |
28 | |
29 | ConstructsWithTupleLeaf(ConstructsWithTupleLeaf const &) { assert(false); } |
30 | ConstructsWithTupleLeaf(ConstructsWithTupleLeaf &&) {} |
31 | |
32 | template <class T> |
33 | ConstructsWithTupleLeaf(T) { |
34 | static_assert(!std::is_same<T, T>::value, |
35 | "Constructor instantiated for type other than int" ); |
36 | } |
37 | }; |
38 | |
39 | // move_only type which triggers the empty base optimization |
40 | struct move_only_ebo { |
41 | move_only_ebo() = default; |
42 | move_only_ebo(move_only_ebo&&) = default; |
43 | }; |
44 | |
45 | // a move_only type which does not trigger the empty base optimization |
46 | struct move_only_large final { |
47 | move_only_large() : value(42) {} |
48 | move_only_large(move_only_large&&) = default; |
49 | int value; |
50 | }; |
51 | |
52 | template <class Elem> |
53 | void test_sfinae() { |
54 | using Tup = std::tuple<Elem>; |
55 | using Alloc = std::allocator<int>; |
56 | using Tag = std::allocator_arg_t; |
57 | // special members |
58 | { |
59 | static_assert(std::is_default_constructible<Tup>::value, "" ); |
60 | static_assert(std::is_move_constructible<Tup>::value, "" ); |
61 | static_assert(!std::is_copy_constructible<Tup>::value, "" ); |
62 | static_assert(!std::is_constructible<Tup, Tup&>::value, "" ); |
63 | } |
64 | // args constructors |
65 | { |
66 | static_assert(std::is_constructible<Tup, Elem&&>::value, "" ); |
67 | static_assert(!std::is_constructible<Tup, Elem const&>::value, "" ); |
68 | static_assert(!std::is_constructible<Tup, Elem&>::value, "" ); |
69 | } |
70 | // uses-allocator special member constructors |
71 | { |
72 | static_assert(std::is_constructible<Tup, Tag, Alloc>::value, "" ); |
73 | static_assert(std::is_constructible<Tup, Tag, Alloc, Tup&&>::value, "" ); |
74 | static_assert(!std::is_constructible<Tup, Tag, Alloc, Tup const&>::value, "" ); |
75 | static_assert(!std::is_constructible<Tup, Tag, Alloc, Tup &>::value, "" ); |
76 | } |
77 | // uses-allocator args constructors |
78 | { |
79 | static_assert(std::is_constructible<Tup, Tag, Alloc, Elem&&>::value, "" ); |
80 | static_assert(!std::is_constructible<Tup, Tag, Alloc, Elem const&>::value, "" ); |
81 | static_assert(!std::is_constructible<Tup, Tag, Alloc, Elem &>::value, "" ); |
82 | } |
83 | } |
84 | |
85 | int main(int, char**) |
86 | { |
87 | { |
88 | typedef std::tuple<> T; |
89 | T t0; |
90 | T t = std::move(t0); |
91 | ((void)t); // Prevent unused warning |
92 | } |
93 | { |
94 | typedef std::tuple<MoveOnly> T; |
95 | T t0(MoveOnly(0)); |
96 | T t = std::move(t0); |
97 | assert(std::get<0>(t) == 0); |
98 | } |
99 | { |
100 | typedef std::tuple<MoveOnly, MoveOnly> T; |
101 | T t0(MoveOnly(0), MoveOnly(1)); |
102 | T t = std::move(t0); |
103 | assert(std::get<0>(t) == 0); |
104 | assert(std::get<1>(t) == 1); |
105 | } |
106 | { |
107 | typedef std::tuple<MoveOnly, MoveOnly, MoveOnly> T; |
108 | T t0(MoveOnly(0), MoveOnly(1), MoveOnly(2)); |
109 | T t = std::move(t0); |
110 | assert(std::get<0>(t) == 0); |
111 | assert(std::get<1>(t) == 1); |
112 | assert(std::get<2>(t) == 2); |
113 | } |
114 | // A bug in tuple caused __tuple_leaf to use its explicit converting constructor |
115 | // as its move constructor. This tests that ConstructsWithTupleLeaf is not called |
116 | // (w/ __tuple_leaf) |
117 | { |
118 | typedef std::tuple<ConstructsWithTupleLeaf> d_t; |
119 | d_t d((ConstructsWithTupleLeaf())); |
120 | d_t d2(static_cast<d_t &&>(d)); |
121 | } |
122 | { |
123 | test_sfinae<move_only_ebo>(); |
124 | test_sfinae<move_only_large>(); |
125 | } |
126 | |
127 | return 0; |
128 | } |
129 | |