Fix the copy constructor in Replaceable
[folly.git] / folly / Replaceable.h
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <initializer_list>
20 #include <new>
21 #include <type_traits>
22 #include <utility>
23
24 #include <folly/Launder.h>
25 #include <folly/Traits.h>
26 #include <folly/Utility.h>
27
28 /**
29  * An instance of `Replaceable<T>` wraps an instance of `T`.
30  *
31  * You access the inner `T` instance with `operator*` and `operator->` (as if
32  * it were a smart pointer).
33  *
34  * `Replaceable<T>` adds no indirection cost and performs no allocations.
35  *
36  * `Replaceable<T>` has the same size and alignment as `T`.
37  *
38  * You can replace the `T` within a `Replaceable<T>` using the `emplace` method
39  * (presuming that it is constructible and destructible without throwing
40  * exceptions). If the destructor or constructor you're using could throw an
41  * exception you should use `Optional<T>` instead, as it's not a logic error
42  * for that to be empty.
43  *
44  * Frequently Asked Questions
45  * ==========================
46  *
47  * Why does this need to be so complicated?
48  * ----------------------------------------
49  *
50  * If a `T` instance contains `const`-qualified member variables or reference
51  * member variables we can't safely replace a `T` instance by destructing it
52  * manually and using placement new. This is because compilers are permitted to
53  * assume that the `const` or reference members of a named, referenced, or
54  * pointed-to object do not change.
55  *
56  * For pointed-to objects in allocated storage you can use the pointer returned
57  * by placement new or use the `launder` function to get a pointer to the new
58  * object.  Note that `launder` doesn't affect its argument, it's still
59  * undefined behaviour to use the original pointer. And none of this helps if
60  * the object is a local or a member variable because the destructor call will
61  * not have been laundered. In summary, this is the only way to use placement
62  * new that is both simple and safe:
63  *
64  *      T* pT = new T(...);
65  *      pT->~T();
66  *      pT = ::new (pT) T(...);
67  *      delete pT;
68  *
69  * What are the other safe solutions to this problem?
70  * --------------------------------------------------
71  *
72  * * Ask the designer of `T` to de-`const` and -`reference` the members of `T`.
73  *  - Makes `T` harder to reason about
74  *  - Can reduce the performance of `T` methods
75  *  - They can refuse to make the change
76  * * Put the `T` on the heap and use a raw/unique/shared pointer.
77  *  - Adds a level of indirection, costing performance.
78  *  - Harder to reason about your code as you need to check for nullptr.
79  * * Put the `T` in an `Optional`.
80  *  - Harder to reason about your code as you need to check for None.
81  * * Pass the problem on, making the new code also not-replaceable
82  *  - Contagion is not really a solution
83  *
84  * Are there downsides to this?
85  * ----------------------------
86  *
87  * There is a potential performance penalty after converting `T` to
88  * `Replaceable<T>` if you have non-`T`-member-function code which repeatedly
89  * examines the value of a `const` or `reference` data member of `T`, because
90  * the compiler now has to look at the value each time whereas previously it
91  * was permitted to load it once up-front and presume that it could never
92  * change.
93  *
94  * Usage notes
95  * ===========
96  *
97  * Don't store a reference to the `T` within a `Replaceable<T>` unless you can
98  * show that its lifetime does not cross an `emplace` call. For safety a
99  * reasonable rule is to always use `operator*()` to get a fresh temporary each
100  * time you need a `T&.
101  *
102  * If you store a pointer to the `T` within a `Replaceable<T>` you **must**
103  * launder it after each call to `emplace` before using it. Again you can
104  * reasonably choose to always use `operator->()` to get a fresh temporary each
105  * time you need a `T*.
106  *
107  * Thus far I haven't thought of a good reason to use `Replaceable<T>` or
108  * `Replaceable<T> const&` as a function parameter type.
109  *
110  * `Replaceable<T>&` can make sense to pass to a function that conditionally
111  * replaces the `T`, where `T` has `const` or reference member variables.
112  *
113  * The main use of `Replaceable<T>` is as a class member type or a local type
114  * in long-running functions.
115  *
116  * It's probably time to rethink your design choices if you end up with
117  * `Replaceable<Replaceable<T>>`, `Optional<Replaceable<T>>`,
118  * `Replaceable<Optional<T>>`, `unique_ptr<Replaceable<T>>` etc. except as a
119  *  result of template expansion.
120  */
121
122 namespace folly {
123 template <class T>
124 class Replaceable;
125
126 namespace replaceable_detail {
127 /* Mixin templates to give `replaceable<T>` the following properties:
128  *
129  * 1. Trivial destructor if `T` has a trivial destructor; user-provided
130  *    otherwise
131  * 2. Move constructor if `T` has a move constructor; deleted otherwise
132  * 3. Move assignment operator if `T` has a move constructor; deleted
133  *    otherwise
134  * 4. Copy constructor if `T` has a copy constructor; deleted otherwise
135  * 5. Copy assignment operator if `T` has a copy constructor; deleted
136  *    otherwise
137  *
138  * Has to be done in this way because we can't `enable_if` them away
139  */
140 template <
141     class T,
142     bool /* true iff destructible */,
143     bool /* true iff trivially destructible */>
144 struct dtor_mixin;
145
146 /* Destructible and trivially destructible */
147 template <class T>
148 struct dtor_mixin<T, true, true> {};
149
150 /* Destructible and not trivially destructible */
151 template <class T>
152 struct dtor_mixin<T, true, false> {
153   dtor_mixin() = default;
154   dtor_mixin(dtor_mixin&&) = default;
155   dtor_mixin(dtor_mixin const&) = default;
156   dtor_mixin& operator=(dtor_mixin&&) = default;
157   dtor_mixin& operator=(dtor_mixin const&) = default;
158   ~dtor_mixin() noexcept(std::is_nothrow_destructible<T>::value) {
159     T* destruct_ptr = launder(reinterpret_cast<T*>(
160         reinterpret_cast<Replaceable<T>*>(this)->storage_));
161     destruct_ptr->~T();
162   }
163 };
164
165 /* Not destructible */
166 template <class T, bool A>
167 struct dtor_mixin<T, false, A> {
168   dtor_mixin() = default;
169   dtor_mixin(dtor_mixin&&) = default;
170   dtor_mixin(dtor_mixin const&) = default;
171   dtor_mixin& operator=(dtor_mixin&&) = default;
172   dtor_mixin& operator=(dtor_mixin const&) = default;
173   ~dtor_mixin() = delete;
174 };
175
176 template <
177     class T,
178     bool /* true iff default constructible */,
179     bool /* true iff move constructible */>
180 struct default_and_move_ctor_mixin;
181
182 /* Not default-constructible and not move-constructible */
183 template <class T>
184 struct default_and_move_ctor_mixin<T, false, false> {
185   default_and_move_ctor_mixin() = delete;
186   default_and_move_ctor_mixin(default_and_move_ctor_mixin&&) = delete;
187   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
188   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
189       default;
190   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin const&) =
191       default;
192
193  protected:
194   inline explicit default_and_move_ctor_mixin(int) {}
195 };
196
197 /* Default-constructible and move-constructible */
198 template <class T>
199 struct default_and_move_ctor_mixin<T, true, true> {
200   inline default_and_move_ctor_mixin() noexcept(
201       std::is_nothrow_constructible<T>::value) {
202     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_) T();
203   }
204   inline default_and_move_ctor_mixin(
205       default_and_move_ctor_mixin&&
206           other) noexcept(std::is_nothrow_constructible<T, T&&>::value) {
207     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
208         T(*std::move(reinterpret_cast<Replaceable<T>&>(other)));
209   }
210   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
211   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
212       default;
213   inline default_and_move_ctor_mixin& operator=(
214       default_and_move_ctor_mixin const&) = default;
215
216  protected:
217   inline explicit default_and_move_ctor_mixin(int) {}
218 };
219
220 /* Default-constructible and not move-constructible */
221 template <class T>
222 struct default_and_move_ctor_mixin<T, true, false> {
223   inline default_and_move_ctor_mixin() noexcept(
224       std::is_nothrow_constructible<T>::value) {
225     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_) T();
226   }
227   default_and_move_ctor_mixin(default_and_move_ctor_mixin&&) = delete;
228   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
229   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
230       default;
231   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin const&) =
232       default;
233
234  protected:
235   inline explicit default_and_move_ctor_mixin(int) {}
236 };
237
238 /* Not default-constructible but is move-constructible */
239 template <class T>
240 struct default_and_move_ctor_mixin<T, false, true> {
241   default_and_move_ctor_mixin() = delete;
242   inline default_and_move_ctor_mixin(
243       default_and_move_ctor_mixin&&
244           other) noexcept(std::is_nothrow_constructible<T, T&&>::value) {
245     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
246         T(*std::move(reinterpret_cast<Replaceable<T>&>(other)));
247   }
248   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
249   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
250       default;
251   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin const&) =
252       default;
253
254  protected:
255   inline explicit default_and_move_ctor_mixin(int) {}
256 };
257
258 template <class T, bool /* true iff destructible and move constructible */>
259 struct move_assignment_mixin;
260
261 /* Not (destructible and move-constructible) */
262 template <class T>
263 struct move_assignment_mixin<T, false> {
264   move_assignment_mixin() = default;
265   move_assignment_mixin(move_assignment_mixin&&) = default;
266   move_assignment_mixin(move_assignment_mixin const&) = default;
267   move_assignment_mixin& operator=(move_assignment_mixin&&) = delete;
268   move_assignment_mixin& operator=(move_assignment_mixin const&) = default;
269 };
270
271 /* Both destructible and move-constructible */
272 template <class T>
273 struct move_assignment_mixin<T, true> {
274   move_assignment_mixin() = default;
275   move_assignment_mixin(move_assignment_mixin&&) = default;
276   move_assignment_mixin(move_assignment_mixin const&) = default;
277   inline move_assignment_mixin&
278   operator=(move_assignment_mixin&& other) noexcept(
279       std::is_nothrow_destructible<T>::value&&
280           std::is_nothrow_move_constructible<T>::value) {
281     T* destruct_ptr = launder(reinterpret_cast<T*>(
282         reinterpret_cast<Replaceable<T>*>(this)->storage_));
283     destruct_ptr->~T();
284     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
285         T(*std::move(reinterpret_cast<Replaceable<T>&>(other)));
286     return *this;
287   }
288   move_assignment_mixin& operator=(move_assignment_mixin const&) = default;
289 };
290
291 template <class T, bool /* true iff copy constructible */>
292 struct copy_ctor_mixin;
293
294 /* Not copy-constructible */
295 template <class T>
296 struct copy_ctor_mixin<T, false> {
297   copy_ctor_mixin() = default;
298   copy_ctor_mixin(copy_ctor_mixin&&) = default;
299   copy_ctor_mixin(copy_ctor_mixin const&) = delete;
300   copy_ctor_mixin& operator=(copy_ctor_mixin&&) = default;
301   copy_ctor_mixin& operator=(copy_ctor_mixin const&) = delete;
302 };
303
304 /* Copy-constructible */
305 template <class T>
306 struct copy_ctor_mixin<T, true> {
307   copy_ctor_mixin() = default;
308   inline copy_ctor_mixin(copy_ctor_mixin const& other) noexcept(
309       std::is_nothrow_constructible<T, T const&>::value) {
310     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
311         T(*reinterpret_cast<Replaceable<T> const&>(other));
312   }
313   copy_ctor_mixin(copy_ctor_mixin&&) = default;
314   copy_ctor_mixin& operator=(copy_ctor_mixin&&) = default;
315   copy_ctor_mixin& operator=(copy_ctor_mixin const&) = default;
316 };
317
318 template <class T, bool /* true iff destructible and copy constructible */>
319 struct copy_assignment_mixin;
320
321 /* Not (destructible and copy-constructible) */
322 template <class T>
323 struct copy_assignment_mixin<T, false> {
324   copy_assignment_mixin() = default;
325   copy_assignment_mixin(copy_assignment_mixin&&) = default;
326   copy_assignment_mixin(copy_assignment_mixin const&) = default;
327   copy_assignment_mixin& operator=(copy_assignment_mixin&&) = default;
328   copy_assignment_mixin& operator=(copy_assignment_mixin const&) = delete;
329 };
330
331 /* Both destructible and copy-constructible */
332 template <class T>
333 struct copy_assignment_mixin<T, true> {
334   copy_assignment_mixin() = default;
335   copy_assignment_mixin(copy_assignment_mixin&&) = default;
336   copy_assignment_mixin(copy_assignment_mixin const&) = default;
337   copy_assignment_mixin& operator=(copy_assignment_mixin&&) = default;
338   inline copy_assignment_mixin&
339   operator=(copy_assignment_mixin const& other) noexcept(
340       std::is_nothrow_destructible<T>::value&&
341           std::is_nothrow_copy_constructible<T>::value) {
342     T* destruct_ptr = launder(reinterpret_cast<T*>(
343         reinterpret_cast<Replaceable<T>*>(this)->storage_));
344     destruct_ptr->~T();
345     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
346         T(*reinterpret_cast<Replaceable<T> const&>(other));
347     return *this;
348   }
349 };
350
351 template <typename T>
352 struct is_constructible_from_replaceable
353     : std::integral_constant<
354           bool,
355           std::is_constructible<T, Replaceable<T>&>::value ||
356               std::is_constructible<T, Replaceable<T>&&>::value ||
357               std::is_constructible<T, const Replaceable<T>&>::value ||
358               std::is_constructible<T, const Replaceable<T>&&>::value> {};
359
360 template <typename T>
361 constexpr bool is_constructible_from_replaceable_v{
362     is_constructible_from_replaceable<T>::value};
363
364 template <typename T>
365 struct is_convertible_from_replaceable
366     : std::integral_constant<
367           bool,
368           std::is_convertible<Replaceable<T>&, T>::value ||
369               std::is_convertible<Replaceable<T>&&, T>::value ||
370               std::is_convertible<const Replaceable<T>&, T>::value ||
371               std::is_convertible<const Replaceable<T>&&, T>::value> {};
372
373 template <typename T>
374 constexpr bool is_convertible_from_replaceable_v{
375     is_convertible_from_replaceable<T>::value};
376 } // namespace replaceable_detail
377
378 // Type trait template to statically test whether a type is a specialization of
379 // Replaceable
380 template <class T>
381 struct is_replaceable : std::false_type {};
382
383 template <class T>
384 struct is_replaceable<Replaceable<T>> : std::true_type {};
385
386 template <class T>
387 constexpr bool is_replaceable_v{is_replaceable<T>::value};
388
389 // Function to make a Replaceable with a type deduced from its input
390 template <class T>
391 constexpr Replaceable<std::decay_t<T>> make_replaceable(T&& t) {
392   return Replaceable<std::decay_t<T>>(std::forward<T>(t));
393 }
394
395 template <class T, class... Args>
396 constexpr Replaceable<T> make_replaceable(Args&&... args) {
397   return Replaceable<T>(in_place, std::forward<Args>(args)...);
398 }
399
400 template <class T, class U, class... Args>
401 constexpr Replaceable<T> make_replaceable(
402     std::initializer_list<U> il,
403     Args&&... args) {
404   return Replaceable<T>(in_place, il, std::forward<Args>(args)...);
405 }
406
407 template <class T>
408 class alignas(T) Replaceable
409     : public replaceable_detail::dtor_mixin<
410           T,
411           std::is_destructible<T>::value,
412           std::is_trivially_destructible<T>::value>,
413       public replaceable_detail::default_and_move_ctor_mixin<
414           T,
415           std::is_default_constructible<T>::value,
416           std::is_move_constructible<T>::value>,
417       public replaceable_detail::
418           copy_ctor_mixin<T, std::is_copy_constructible<T>::value>,
419       public replaceable_detail::move_assignment_mixin<
420           T,
421           std::is_destructible<T>::value &&
422               std::is_move_constructible<T>::value>,
423       public replaceable_detail::copy_assignment_mixin<
424           T,
425           std::is_destructible<T>::value &&
426               std::is_copy_constructible<T>::value> {
427   using ctor_base = replaceable_detail::default_and_move_ctor_mixin<
428       T,
429       std::is_constructible<T>::value,
430       std::is_move_constructible<T>::value>;
431
432  public:
433   using value_type = T;
434
435   /* Rule-of-zero default- copy- and move- constructors. The ugly code to make
436    * these work are above, in namespace folly::replaceable_detail.
437    */
438   constexpr Replaceable() = default;
439   constexpr Replaceable(const Replaceable&) = default;
440   constexpr Replaceable(Replaceable&&) = default;
441
442   /* Rule-of-zero copy- and move- assignment operators. The ugly code to make
443    * these work are above, in namespace folly::replaceable_detail.
444    *
445    * Note - these destruct the `T` and then in-place construct a new one based
446    * on what is in the other replaceable; they do not invoke the assignment
447    * operator of `T`.
448    */
449   Replaceable& operator=(const Replaceable&) = default;
450   Replaceable& operator=(Replaceable&&) = default;
451
452   /* Rule-of-zero destructor. The ugly code to make this work is above, in
453    * namespace folly::replaceable_detail.
454    */
455   ~Replaceable() = default;
456
457   /**
458    * Constructors; these are modeled very closely on the definition of
459    * `std::optional` in C++17.
460    */
461   template <
462       class... Args,
463       std::enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
464   constexpr explicit Replaceable(in_place_t, Args&&... args)
465       // clang-format off
466       noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
467       // clang-format on
468       : ctor_base(0) {
469     ::new (storage_) T(std::forward<Args>(args)...);
470   }
471
472   template <
473       class U,
474       class... Args,
475       std::enable_if_t<
476           std::is_constructible<T, std::initializer_list<U>, Args&&...>::value,
477           int> = 0>
478   constexpr explicit Replaceable(
479       in_place_t,
480       std::initializer_list<U> il,
481       Args&&... args)
482       // clang-format off
483       noexcept(std::is_nothrow_constructible<
484           T,
485           std::initializer_list<U>,
486           Args&&...>::value)
487       // clang-format on
488       : ctor_base(0) {
489     ::new (storage_) T(il, std::forward<Args>(args)...);
490   }
491
492   template <
493       class U = T,
494       std::enable_if_t<
495           std::is_constructible<T, U&&>::value &&
496               !std::is_same<std::decay_t<U>, in_place_t>::value &&
497               !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
498               std::is_convertible<U&&, T>::value,
499           int> = 0>
500   constexpr /* implicit */ Replaceable(U&& other)
501       // clang-format off
502       noexcept(std::is_nothrow_constructible<T, U&&>::value)
503       // clang-format on
504       : ctor_base(0) {
505     ::new (storage_) T(std::forward<U>(other));
506   }
507
508   template <
509       class U = T,
510       std::enable_if_t<
511           std::is_constructible<T, U&&>::value &&
512               !std::is_same<std::decay_t<U>, in_place_t>::value &&
513               !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
514               !std::is_convertible<U&&, T>::value,
515           int> = 0>
516   explicit constexpr Replaceable(U&& other)
517       // clang-format off
518       noexcept(std::is_nothrow_constructible<T, U&&>::value)
519       // clang-format on
520       : ctor_base(0) {
521     ::new (storage_) T(std::forward<U>(other));
522   }
523
524   template <
525       class U,
526       std::enable_if_t<
527           std::is_constructible<T, const U&>::value &&
528               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
529               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
530               std::is_convertible<const U&, T>::value,
531           int> = 0>
532   /* implicit */ Replaceable(const Replaceable<U>& other)
533       // clang-format off
534       noexcept(std::is_nothrow_constructible<T, U const&>::value)
535       // clang-format on
536       : ctor_base(0) {
537     ::new (storage_) T(*other);
538   }
539
540   template <
541       class U,
542       std::enable_if_t<
543           std::is_constructible<T, const U&>::value &&
544               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
545               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
546               !std::is_convertible<const U&, T>::value,
547           int> = 0>
548   explicit Replaceable(const Replaceable<U>& other)
549       // clang-format off
550       noexcept(std::is_nothrow_constructible<T, U const&>::value)
551       // clang-format on
552       : ctor_base(0) {
553     ::new (storage_) T(*other);
554   }
555
556   template <
557       class U,
558       std::enable_if_t<
559           std::is_constructible<T, U&&>::value &&
560               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
561               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
562               std::is_convertible<U&&, T>::value,
563           int> = 0>
564   /* implicit */ Replaceable(Replaceable<U>&& other)
565       // clang-format off
566       noexcept(std::is_nothrow_constructible<T, U&&>::value)
567       // clang-format on
568       : ctor_base(0) {
569     ::new (storage_) T(std::move(*other));
570   }
571
572   template <
573       class U,
574       std::enable_if_t<
575           std::is_constructible<T, U&&>::value &&
576               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
577               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
578               !std::is_convertible<U&&, T>::value,
579           int> = 0>
580   explicit Replaceable(Replaceable<U>&& other)
581       // clang-format off
582       noexcept(std::is_nothrow_constructible<T, U&&>::value)
583       // clang-format on
584       : ctor_base(0) {
585     ::new (storage_) T(std::move(*other));
586   }
587
588   /**
589    * `emplace` destructs the contained object and in-place constructs the
590    * replacement.
591    *
592    * The destructor must not throw (as usual). The constructor must not throw
593    * because that would violate the invariant that a `Replaceable<T>` always
594    * contains a T instance.
595    *
596    * As these methods are `noexcept` the program will be terminated if an
597    * exception is thrown. If you are encountering this issue you should look at
598    * using `Optional` instead.
599    */
600   template <class... Args>
601   T& emplace(Args&&... args) noexcept {
602     T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
603     destruct_ptr->~T();
604     return *::new (storage_) T(std::forward<Args>(args)...);
605   }
606
607   template <class U, class... Args>
608   T& emplace(std::initializer_list<U> il, Args&&... args) noexcept {
609     T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
610     destruct_ptr->~T();
611     return *::new (storage_) T(il, std::forward<Args>(args)...);
612   }
613
614   /**
615    * `swap` just calls `swap(T&, T&)`.
616    *
617    * Should be `noexcept(std::is_nothrow_swappable<T>::value)` but we don't
618    * depend on C++17 features.
619    */
620   void swap(Replaceable& other) {
621     using std::swap;
622     swap(*(*this), *other);
623   }
624
625   /**
626    * Methods to access the contained object. Intended to be very unsurprising.
627    */
628   constexpr const T* operator->() const {
629     return launder(reinterpret_cast<T const*>(storage_));
630   }
631
632   constexpr T* operator->() {
633     return launder(reinterpret_cast<T*>(storage_));
634   }
635
636   constexpr const T& operator*() const & {
637     return *launder(reinterpret_cast<T const*>(storage_));
638   }
639
640   constexpr T& operator*() & {
641     return *launder(reinterpret_cast<T*>(storage_));
642   }
643
644   constexpr T&& operator*() && {
645     return std::move(*launder(reinterpret_cast<T*>(storage_)));
646   }
647
648   constexpr const T&& operator*() const && {
649     return std::move(*launder(reinterpret_cast<T const*>(storage_)));
650   }
651
652  private:
653   friend struct replaceable_detail::dtor_mixin<
654       T,
655       std::is_destructible<T>::value,
656       std::is_trivially_destructible<T>::value>;
657   friend struct replaceable_detail::default_and_move_ctor_mixin<
658       T,
659       std::is_default_constructible<T>::value,
660       std::is_move_constructible<T>::value>;
661   friend struct replaceable_detail::
662       copy_ctor_mixin<T, std::is_constructible<T, T const&>::value>;
663   friend struct replaceable_detail::move_assignment_mixin<
664       T,
665       std::is_destructible<T>::value && std::is_move_constructible<T>::value>;
666   friend struct replaceable_detail::copy_assignment_mixin<
667       T,
668       std::is_destructible<T>::value && std::is_copy_constructible<T>::value>;
669   std::aligned_storage_t<sizeof(T), alignof(T)> storage_[1];
670 };
671
672 #if __cplusplus > 201402L
673 // C++17 allows us to define a deduction guide:
674 template <class T>
675 Replaceable(T)->Replaceable<T>;
676 #endif
677 } // namespace folly