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// UNSUPPORTED: c++03, c++11, c++14
10
11// <any>
12
13// template <class T, class ...Args> T& emplace(Args&&...);
14// template <class T, class U, class ...Args>
15// T& emplace(initializer_list<U>, Args&&...);
16
17#include <any>
18#include <cassert>
19
20#include "any_helpers.h"
21#include "count_new.h"
22#include "test_macros.h"
23
24struct Tracked {
25 static int count;
26 Tracked() { ++count; }
27 Tracked(Tracked const&) noexcept { ++count; }
28 Tracked& operator=(Tracked const&) = default;
29 ~Tracked() { --count; }
30};
31int Tracked::count = 0;
32
33template <class Type>
34void test_emplace_type() {
35 // constructing from a small type should perform no allocations.
36 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
37 assert(Type::count == 0);
38 Type::reset();
39 {
40 std::any a(std::in_place_type<Tracked>);
41 assert(Tracked::count == 1);
42
43 auto &v = a.emplace<Type>();
44 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
45 assert(&v == std::any_cast<Type>(&a));
46
47 assert(Tracked::count == 0);
48 assert(Type::count == 1);
49 assert(Type::copied == 0);
50 assert(Type::moved == 0);
51 assertContains<Type>(a, 0);
52 }
53 assert(Type::count == 0);
54 Type::reset();
55 {
56 std::any a(std::in_place_type<Tracked>);
57 assert(Tracked::count == 1);
58
59 auto &v = a.emplace<Type>(101);
60 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
61 assert(&v == std::any_cast<Type>(&a));
62
63 assert(Tracked::count == 0);
64 assert(Type::count == 1);
65 assert(Type::copied == 0);
66 assert(Type::moved == 0);
67 assertContains<Type>(a, 101);
68 }
69 assert(Type::count == 0);
70 Type::reset();
71 {
72 std::any a(std::in_place_type<Tracked>);
73 assert(Tracked::count == 1);
74
75 auto &v = a.emplace<Type>(-1, 42, -1);
76 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
77 assert(&v == std::any_cast<Type>(&a));
78
79 assert(Tracked::count == 0);
80 assert(Type::count == 1);
81 assert(Type::copied == 0);
82 assert(Type::moved == 0);
83 assertContains<Type>(a, 42);
84 }
85 assert(Type::count == 0);
86 Type::reset();
87}
88
89template <class Type>
90void test_emplace_type_tracked() {
91 // constructing from a small type should perform no allocations.
92 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
93 {
94 std::any a(std::in_place_type<Tracked>);
95 assert(Tracked::count == 1);
96 auto &v = a.emplace<Type>();
97 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
98 assert(&v == std::any_cast<Type>(&a));
99
100 assert(Tracked::count == 0);
101 assertArgsMatch<Type>(a);
102 }
103 {
104 std::any a(std::in_place_type<Tracked>);
105 assert(Tracked::count == 1);
106 auto &v = a.emplace<Type>(-1, 42, -1);
107 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
108 assert(&v == std::any_cast<Type>(&a));
109
110 assert(Tracked::count == 0);
111 assertArgsMatch<Type, int, int, int>(a);
112 }
113 // initializer_list constructor tests
114 {
115 std::any a(std::in_place_type<Tracked>);
116 assert(Tracked::count == 1);
117 auto &v = a.emplace<Type>({-1, 42, -1});
118 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
119 assert(&v == std::any_cast<Type>(&a));
120
121 assert(Tracked::count == 0);
122 assertArgsMatch<Type, std::initializer_list<int>>(a);
123 }
124 {
125 int x = 42;
126 std::any a(std::in_place_type<Tracked>);
127 assert(Tracked::count == 1);
128 auto &v = a.emplace<Type>({-1, 42, -1}, x);
129 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
130 assert(&v == std::any_cast<Type>(&a));
131
132 assert(Tracked::count == 0);
133 assertArgsMatch<Type, std::initializer_list<int>, int&>(a);
134 }
135}
136
137#ifndef TEST_HAS_NO_EXCEPTIONS
138
139struct SmallThrows {
140 SmallThrows(int) { throw 42; }
141 SmallThrows(std::initializer_list<int>, int) { throw 42; }
142};
143static_assert(IsSmallObject<SmallThrows>::value, "");
144
145struct LargeThrows {
146 LargeThrows(int) { throw 42; }
147 LargeThrows(std::initializer_list<int>, int) { throw 42; }
148 int data[sizeof(std::any)];
149};
150static_assert(!IsSmallObject<LargeThrows>::value, "");
151
152template <class Type>
153void test_emplace_throws()
154{
155 // any stores small type
156 {
157 std::any a(small{42});
158 assert(small::count == 1);
159 try {
160 auto &v = a.emplace<Type>(101);
161 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
162 assert(false);
163 } catch (int const&) {
164 }
165 assert(small::count == 0);
166 }
167 {
168 std::any a(small{42});
169 assert(small::count == 1);
170 try {
171 auto &v = a.emplace<Type>({1, 2, 3}, 101);
172 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
173 assert(false);
174 } catch (int const&) {
175 }
176 assert(small::count == 0);
177 }
178 // any stores large type
179 {
180 std::any a(large{42});
181 assert(large::count == 1);
182 try {
183 auto &v = a.emplace<Type>(101);
184 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
185 assert(false);
186 } catch (int const&) {
187 }
188 assert(large::count == 0);
189 }
190 {
191 std::any a(large{42});
192 assert(large::count == 1);
193 try {
194 auto &v = a.emplace<Type>({1, 2, 3}, 101);
195 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
196 assert(false);
197 } catch (int const&) {
198 }
199 assert(large::count == 0);
200 }
201}
202
203#endif
204
205template <class T, class ...Args>
206constexpr auto has_emplace(int)
207 -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; }
208
209template <class ...Args>
210constexpr bool has_emplace(long) { return false; }
211
212template <class ...Args>
213constexpr bool has_emplace() { return has_emplace<Args...>(0); }
214
215
216template <class T, class IT, class ...Args>
217constexpr auto has_emplace_init_list(int)
218 -> decltype(std::any{}.emplace<T>(
219 {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()},
220 std::declval<Args>()...), true) { return true; }
221
222template <class ...Args>
223constexpr bool has_emplace_init_list(long) { return false; }
224
225template <class ...Args>
226constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); }
227
228
229void test_emplace_sfinae_constraints() {
230 {
231 static_assert(has_emplace<int>(), "");
232 static_assert(has_emplace<int, int>(), "");
233 static_assert(!has_emplace<int, int, int>(), "not constructible");
234 static_assert(!has_emplace_init_list<int, int>(), "not constructible from il");
235 }
236 {
237 static_assert(has_emplace<small>(), "");
238 static_assert(has_emplace<large>(), "");
239 static_assert(!has_emplace<small, void*>(), "");
240 static_assert(!has_emplace<large, void*>(), "");
241
242 static_assert(has_emplace_init_list<small, int>(), "");
243 static_assert(has_emplace_init_list<large, int>(), "");
244 static_assert(!has_emplace_init_list<small, void*>(), "");
245 static_assert(!has_emplace_init_list<large, void*>(), "");
246 }
247 {
248 // Test that the emplace SFINAE's away when the
249 // argument is non-copyable
250 struct NoCopy {
251 NoCopy() = default;
252 NoCopy(NoCopy const&) = delete;
253 NoCopy(int) {}
254 NoCopy(std::initializer_list<int>, int, int) {}
255 };
256 static_assert(!has_emplace<NoCopy>(), "");
257 static_assert(!has_emplace<NoCopy, int>(), "");
258 static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), "");
259 static_assert(!has_emplace<NoCopy&>(), "");
260 static_assert(!has_emplace<NoCopy&, int>(), "");
261 static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), "");
262 static_assert(!has_emplace<NoCopy&&>(), "");
263 static_assert(!has_emplace<NoCopy&&, int>(), "");
264 static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), "");
265
266 }
267}
268
269int main(int, char**) {
270 test_emplace_type<small>();
271 test_emplace_type<large>();
272 test_emplace_type<small_throws_on_copy>();
273 test_emplace_type<large_throws_on_copy>();
274 test_emplace_type<throws_on_move>();
275 test_emplace_type_tracked<small_tracked_t>();
276 test_emplace_type_tracked<large_tracked_t>();
277 test_emplace_sfinae_constraints();
278#ifndef TEST_HAS_NO_EXCEPTIONS
279 test_emplace_throws<SmallThrows>();
280 test_emplace_throws<LargeThrows>();
281#endif
282
283 return 0;
284}
285

source code of libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp