/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include namespace folly { /** * Class template that wraps a reference to an rvalue. Similar to * std::reference_wrapper but with three important differences: * * 1) folly::rvalue_reference_wrappers can only be moved, not copied; * 2) the get() function and the conversion-to-T operator are destructive and * not const, they invalidate the wrapper; * 3) the constructor-from-T is explicit. * * These restrictions are designed to make it harder to accidentally create a * a dangling rvalue reference, or to use an rvalue reference multiple times. * (Using an rvalue reference typically implies invalidation of the target * object, such as move-assignment to another object.) * * @seealso folly::rref */ template class rvalue_reference_wrapper { public: using type = T; /** * Default constructor. Creates an invalid reference. Must be move-assigned * to in order to be come valid. */ rvalue_reference_wrapper() noexcept : ptr_(nullptr) {} /** * Explicit constructor to make it harder to accidentally create a dangling * reference to a temporary. */ explicit rvalue_reference_wrapper(T&& ref) noexcept : ptr_(std::addressof(ref)) {} /** * No construction from lvalue reference. Use std::move. */ explicit rvalue_reference_wrapper(T&) noexcept = delete; /** * Destructive move construction. */ rvalue_reference_wrapper(rvalue_reference_wrapper&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; } /** * Destructive move assignment. */ rvalue_reference_wrapper& operator=( rvalue_reference_wrapper&& other) noexcept { ptr_ = other.ptr_; other.ptr_ = nullptr; return *this; } /** * Implicit conversion to raw reference. Destructive. */ /* implicit */ operator T &&() && noexcept { return static_cast(*this).get(); } /** * Explicit unwrap. Destructive. */ T&& get() && noexcept { assert(valid()); T& ref = *ptr_; ptr_ = nullptr; return static_cast(ref); } /** * Calls the callable object to whom reference is stored. Only available if * the wrapped reference points to a callable object. Destructive. */ template decltype(auto) operator()(Args&&... args) && noexcept(noexcept(std::declval()(std::forward(args)...))) { return static_cast(*this).get()( std::forward(args)...); } /** * Check whether wrapped reference is valid. */ bool valid() const noexcept { return ptr_ != nullptr; } private: // Disallow copy construction and copy assignment, to make it harder to // accidentally use an rvalue reference multiple times. rvalue_reference_wrapper(const rvalue_reference_wrapper&) = delete; rvalue_reference_wrapper& operator=(const rvalue_reference_wrapper&) = delete; T* ptr_; }; /** * Create a folly::rvalue_reference_wrapper. Analogous to std::ref(). * * Warning: folly::rvalue_reference_wrappers are potentially dangerous, because * they can easily be used to capture references to temporary values. Users must * ensure that the target object outlives the reference wrapper. * * @example * class Object {}; * void f(Object&&); * // BAD * void g() { * auto ref = folly::rref(Object{}); // create reference to temporary * f(std::move(ref)); // pass dangling reference * } * // GOOD * void h() { * Object o; * auto ref = folly::rref(std::move(o)); * f(std::move(ref)); * } */ template rvalue_reference_wrapper rref(T&& value) noexcept { return rvalue_reference_wrapper(std::move(value)); } template rvalue_reference_wrapper rref(T&) noexcept = delete; } // namespace folly