logging: fix compiler compatibility for one more constexpr function
[folly.git] / folly / Functional.h
1 /*
2  * Copyright 2017-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 <cassert>
20 #include <memory>
21 #include <utility>
22
23 namespace folly {
24
25 /**
26  * Class template that wraps a reference to an rvalue. Similar to
27  * std::reference_wrapper but with three important differences:
28  *
29  * 1) folly::rvalue_reference_wrappers can only be moved, not copied;
30  * 2) the get() function and the conversion-to-T operator are destructive and
31  *    not const, they invalidate the wrapper;
32  * 3) the constructor-from-T is explicit.
33  *
34  * These restrictions are designed to make it harder to accidentally create a
35  * a dangling rvalue reference, or to use an rvalue reference multiple times.
36  * (Using an rvalue reference typically implies invalidation of the target
37  * object, such as move-assignment to another object.)
38  *
39  * @seealso folly::rref
40  */
41 template <class T>
42 class rvalue_reference_wrapper {
43  public:
44   using type = T;
45
46   /**
47    * Default constructor. Creates an invalid reference. Must be move-assigned
48    * to in order to be come valid.
49    */
50   rvalue_reference_wrapper() noexcept : ptr_(nullptr) {}
51
52   /**
53    * Explicit constructor to make it harder to accidentally create a dangling
54    * reference to a temporary.
55    */
56   explicit rvalue_reference_wrapper(T&& ref) noexcept
57       : ptr_(std::addressof(ref)) {}
58
59   /**
60    * No construction from lvalue reference. Use std::move.
61    */
62   explicit rvalue_reference_wrapper(T&) noexcept = delete;
63
64   /**
65    * Destructive move construction.
66    */
67   rvalue_reference_wrapper(rvalue_reference_wrapper<T>&& other) noexcept
68       : ptr_(other.ptr_) {
69     other.ptr_ = nullptr;
70   }
71
72   /**
73    * Destructive move assignment.
74    */
75   rvalue_reference_wrapper& operator=(
76       rvalue_reference_wrapper&& other) noexcept {
77     ptr_ = other.ptr_;
78     other.ptr_ = nullptr;
79     return *this;
80   }
81
82   /**
83    * Implicit conversion to raw reference. Destructive.
84    */
85   /* implicit */ operator T &&() && noexcept {
86     return static_cast<rvalue_reference_wrapper&&>(*this).get();
87   }
88
89   /**
90    * Explicit unwrap. Destructive.
91    */
92   T&& get() && noexcept {
93     assert(valid());
94     T& ref = *ptr_;
95     ptr_ = nullptr;
96     return static_cast<T&&>(ref);
97   }
98
99   /**
100    * Calls the callable object to whom reference is stored. Only available if
101    * the wrapped reference points to a callable object. Destructive.
102    */
103   template <class... Args>
104   decltype(auto) operator()(Args&&... args) &&
105       noexcept(noexcept(std::declval<T>()(std::forward<Args>(args)...))) {
106     return static_cast<rvalue_reference_wrapper&&>(*this).get()(
107         std::forward<Args>(args)...);
108   }
109
110   /**
111    * Check whether wrapped reference is valid.
112    */
113   bool valid() const noexcept {
114     return ptr_ != nullptr;
115   }
116
117  private:
118   // Disallow copy construction and copy assignment, to make it harder to
119   // accidentally use an rvalue reference multiple times.
120   rvalue_reference_wrapper(const rvalue_reference_wrapper&) = delete;
121   rvalue_reference_wrapper& operator=(const rvalue_reference_wrapper&) = delete;
122
123   T* ptr_;
124 };
125
126 /**
127  * Create a folly::rvalue_reference_wrapper. Analogous to std::ref().
128  *
129  * Warning: folly::rvalue_reference_wrappers are potentially dangerous, because
130  * they can easily be used to capture references to temporary values. Users must
131  * ensure that the target object outlives the reference wrapper.
132  *
133  * @example
134  *   class Object {};
135  *   void f(Object&&);
136  *   // BAD
137  *   void g() {
138  *     auto ref = folly::rref(Object{});  // create reference to temporary
139  *     f(std::move(ref));                 // pass dangling reference
140  *   }
141  *   // GOOD
142  *   void h() {
143  *     Object o;
144  *     auto ref = folly::rref(std::move(o));
145  *     f(std::move(ref));
146  *   }
147  */
148 template <typename T>
149 rvalue_reference_wrapper<T> rref(T&& value) noexcept {
150   return rvalue_reference_wrapper<T>(std::move(value));
151 }
152 template <typename T>
153 rvalue_reference_wrapper<T> rref(T&) noexcept = delete;
154 }