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