Remove template helper constants
[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 struct is_convertible_from_replaceable
362     : std::integral_constant<
363           bool,
364           std::is_convertible<Replaceable<T>&, T>::value ||
365               std::is_convertible<Replaceable<T>&&, T>::value ||
366               std::is_convertible<const Replaceable<T>&, T>::value ||
367               std::is_convertible<const Replaceable<T>&&, T>::value> {};
368 } // namespace replaceable_detail
369
370 // Type trait template to statically test whether a type is a specialization of
371 // Replaceable
372 template <class T>
373 struct is_replaceable : std::false_type {};
374
375 template <class T>
376 struct is_replaceable<Replaceable<T>> : std::true_type {};
377
378 // Function to make a Replaceable with a type deduced from its input
379 template <class T>
380 constexpr Replaceable<std::decay_t<T>> make_replaceable(T&& t) {
381   return Replaceable<std::decay_t<T>>(std::forward<T>(t));
382 }
383
384 template <class T, class... Args>
385 constexpr Replaceable<T> make_replaceable(Args&&... args) {
386   return Replaceable<T>(in_place, std::forward<Args>(args)...);
387 }
388
389 template <class T, class U, class... Args>
390 constexpr Replaceable<T> make_replaceable(
391     std::initializer_list<U> il,
392     Args&&... args) {
393   return Replaceable<T>(in_place, il, std::forward<Args>(args)...);
394 }
395
396 template <class T>
397 class alignas(T) Replaceable
398     : public replaceable_detail::dtor_mixin<
399           T,
400           std::is_destructible<T>::value,
401           std::is_trivially_destructible<T>::value>,
402       public replaceable_detail::default_and_move_ctor_mixin<
403           T,
404           std::is_default_constructible<T>::value,
405           std::is_move_constructible<T>::value>,
406       public replaceable_detail::
407           copy_ctor_mixin<T, std::is_copy_constructible<T>::value>,
408       public replaceable_detail::move_assignment_mixin<
409           T,
410           std::is_destructible<T>::value &&
411               std::is_move_constructible<T>::value>,
412       public replaceable_detail::copy_assignment_mixin<
413           T,
414           std::is_destructible<T>::value &&
415               std::is_copy_constructible<T>::value> {
416   using ctor_base = replaceable_detail::default_and_move_ctor_mixin<
417       T,
418       std::is_constructible<T>::value,
419       std::is_move_constructible<T>::value>;
420
421  public:
422   using value_type = T;
423
424   /* Rule-of-zero default- copy- and move- constructors. The ugly code to make
425    * these work are above, in namespace folly::replaceable_detail.
426    */
427   constexpr Replaceable() = default;
428   constexpr Replaceable(const Replaceable&) = default;
429   constexpr Replaceable(Replaceable&&) = default;
430
431   /* Rule-of-zero copy- and move- assignment operators. The ugly code to make
432    * these work are above, in namespace folly::replaceable_detail.
433    *
434    * Note - these destruct the `T` and then in-place construct a new one based
435    * on what is in the other replaceable; they do not invoke the assignment
436    * operator of `T`.
437    */
438   Replaceable& operator=(const Replaceable&) = default;
439   Replaceable& operator=(Replaceable&&) = default;
440
441   /* Rule-of-zero destructor. The ugly code to make this work is above, in
442    * namespace folly::replaceable_detail.
443    */
444   ~Replaceable() = default;
445
446   /**
447    * Constructors; these are modeled very closely on the definition of
448    * `std::optional` in C++17.
449    */
450   template <
451       class... Args,
452       std::enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
453   constexpr explicit Replaceable(in_place_t, Args&&... args)
454       // clang-format off
455       noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
456       // clang-format on
457       : ctor_base(0) {
458     ::new (storage_) T(std::forward<Args>(args)...);
459   }
460
461   template <
462       class U,
463       class... Args,
464       std::enable_if_t<
465           std::is_constructible<T, std::initializer_list<U>, Args&&...>::value,
466           int> = 0>
467   constexpr explicit Replaceable(
468       in_place_t,
469       std::initializer_list<U> il,
470       Args&&... args)
471       // clang-format off
472       noexcept(std::is_nothrow_constructible<
473           T,
474           std::initializer_list<U>,
475           Args&&...>::value)
476       // clang-format on
477       : ctor_base(0) {
478     ::new (storage_) T(il, std::forward<Args>(args)...);
479   }
480
481   template <
482       class U = T,
483       std::enable_if_t<
484           std::is_constructible<T, U&&>::value &&
485               !std::is_same<std::decay_t<U>, in_place_t>::value &&
486               !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
487               std::is_convertible<U&&, T>::value,
488           int> = 0>
489   constexpr /* implicit */ Replaceable(U&& other)
490       // clang-format off
491       noexcept(std::is_nothrow_constructible<T, U&&>::value)
492       // clang-format on
493       : ctor_base(0) {
494     ::new (storage_) T(std::forward<U>(other));
495   }
496
497   template <
498       class U = T,
499       std::enable_if_t<
500           std::is_constructible<T, U&&>::value &&
501               !std::is_same<std::decay_t<U>, in_place_t>::value &&
502               !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
503               !std::is_convertible<U&&, T>::value,
504           int> = 0>
505   explicit constexpr Replaceable(U&& other)
506       // clang-format off
507       noexcept(std::is_nothrow_constructible<T, U&&>::value)
508       // clang-format on
509       : ctor_base(0) {
510     ::new (storage_) T(std::forward<U>(other));
511   }
512
513   template <
514       class U,
515       std::enable_if_t<
516           std::is_constructible<T, const U&>::value &&
517               !replaceable_detail::is_constructible_from_replaceable<
518                   T>::value &&
519               !replaceable_detail::is_convertible_from_replaceable<T>::value &&
520               std::is_convertible<const U&, T>::value,
521           int> = 0>
522   /* implicit */ Replaceable(const Replaceable<U>& other)
523       // clang-format off
524       noexcept(std::is_nothrow_constructible<T, U const&>::value)
525       // clang-format on
526       : ctor_base(0) {
527     ::new (storage_) T(*other);
528   }
529
530   template <
531       class U,
532       std::enable_if_t<
533           std::is_constructible<T, const U&>::value &&
534               !replaceable_detail::is_constructible_from_replaceable<
535                   T>::value &&
536               !replaceable_detail::is_convertible_from_replaceable<T>::value &&
537               !std::is_convertible<const U&, T>::value,
538           int> = 0>
539   explicit Replaceable(const Replaceable<U>& other)
540       // clang-format off
541       noexcept(std::is_nothrow_constructible<T, U const&>::value)
542       // clang-format on
543       : ctor_base(0) {
544     ::new (storage_) T(*other);
545   }
546
547   template <
548       class U,
549       std::enable_if_t<
550           std::is_constructible<T, U&&>::value &&
551               !replaceable_detail::is_constructible_from_replaceable<
552                   T>::value &&
553               !replaceable_detail::is_convertible_from_replaceable<T>::value &&
554               std::is_convertible<U&&, T>::value,
555           int> = 0>
556   /* implicit */ Replaceable(Replaceable<U>&& other)
557       // clang-format off
558       noexcept(std::is_nothrow_constructible<T, U&&>::value)
559       // clang-format on
560       : ctor_base(0) {
561     ::new (storage_) T(std::move(*other));
562   }
563
564   template <
565       class U,
566       std::enable_if_t<
567           std::is_constructible<T, U&&>::value &&
568               !replaceable_detail::is_constructible_from_replaceable<
569                   T>::value &&
570               !replaceable_detail::is_convertible_from_replaceable<T>::value &&
571               !std::is_convertible<U&&, T>::value,
572           int> = 0>
573   explicit Replaceable(Replaceable<U>&& other)
574       // clang-format off
575       noexcept(std::is_nothrow_constructible<T, U&&>::value)
576       // clang-format on
577       : ctor_base(0) {
578     ::new (storage_) T(std::move(*other));
579   }
580
581   /**
582    * `emplace` destructs the contained object and in-place constructs the
583    * replacement.
584    *
585    * The destructor must not throw (as usual). The constructor must not throw
586    * because that would violate the invariant that a `Replaceable<T>` always
587    * contains a T instance.
588    *
589    * As these methods are `noexcept` the program will be terminated if an
590    * exception is thrown. If you are encountering this issue you should look at
591    * using `Optional` instead.
592    */
593   template <class... Args>
594   T& emplace(Args&&... args) noexcept {
595     T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
596     destruct_ptr->~T();
597     return *::new (storage_) T(std::forward<Args>(args)...);
598   }
599
600   template <class U, class... Args>
601   T& emplace(std::initializer_list<U> il, Args&&... args) noexcept {
602     T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
603     destruct_ptr->~T();
604     return *::new (storage_) T(il, std::forward<Args>(args)...);
605   }
606
607   /**
608    * `swap` just calls `swap(T&, T&)`.
609    *
610    * Should be `noexcept(std::is_nothrow_swappable<T>::value)` but we don't
611    * depend on C++17 features.
612    */
613   void swap(Replaceable& other) {
614     using std::swap;
615     swap(*(*this), *other);
616   }
617
618   /**
619    * Methods to access the contained object. Intended to be very unsurprising.
620    */
621   constexpr const T* operator->() const {
622     return launder(reinterpret_cast<T const*>(storage_));
623   }
624
625   constexpr T* operator->() {
626     return launder(reinterpret_cast<T*>(storage_));
627   }
628
629   constexpr const T& operator*() const & {
630     return *launder(reinterpret_cast<T const*>(storage_));
631   }
632
633   constexpr T& operator*() & {
634     return *launder(reinterpret_cast<T*>(storage_));
635   }
636
637   constexpr T&& operator*() && {
638     return std::move(*launder(reinterpret_cast<T*>(storage_)));
639   }
640
641   constexpr const T&& operator*() const && {
642     return std::move(*launder(reinterpret_cast<T const*>(storage_)));
643   }
644
645  private:
646   friend struct replaceable_detail::dtor_mixin<
647       T,
648       std::is_destructible<T>::value,
649       std::is_trivially_destructible<T>::value>;
650   friend struct replaceable_detail::default_and_move_ctor_mixin<
651       T,
652       std::is_default_constructible<T>::value,
653       std::is_move_constructible<T>::value>;
654   friend struct replaceable_detail::
655       copy_ctor_mixin<T, std::is_constructible<T, T const&>::value>;
656   friend struct replaceable_detail::move_assignment_mixin<
657       T,
658       std::is_destructible<T>::value && std::is_move_constructible<T>::value>;
659   friend struct replaceable_detail::copy_assignment_mixin<
660       T,
661       std::is_destructible<T>::value && std::is_copy_constructible<T>::value>;
662   std::aligned_storage_t<sizeof(T), alignof(T)> storage_[1];
663 };
664
665 #if __cplusplus > 201402L
666 // C++17 allows us to define a deduction guide:
667 template <class T>
668 Replaceable(T)->Replaceable<T>;
669 #endif
670 } // namespace folly