155 lines
4.4 KiB
C++
155 lines
4.4 KiB
C++
/*
|
|
* Copyright 2017-present Facebook, Inc.
|
|
*
|
|
* 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 <cassert>
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
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 T>
|
|
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<T>&& 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<rvalue_reference_wrapper&&>(*this).get();
|
|
}
|
|
|
|
/**
|
|
* Explicit unwrap. Destructive.
|
|
*/
|
|
T&& get() && noexcept {
|
|
assert(valid());
|
|
T& ref = *ptr_;
|
|
ptr_ = nullptr;
|
|
return static_cast<T&&>(ref);
|
|
}
|
|
|
|
/**
|
|
* Calls the callable object to whom reference is stored. Only available if
|
|
* the wrapped reference points to a callable object. Destructive.
|
|
*/
|
|
template <class... Args>
|
|
decltype(auto) operator()(Args&&... args) &&
|
|
noexcept(noexcept(std::declval<T>()(std::forward<Args>(args)...))) {
|
|
return static_cast<rvalue_reference_wrapper&&>(*this).get()(
|
|
std::forward<Args>(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 <typename T>
|
|
rvalue_reference_wrapper<T> rref(T&& value) noexcept {
|
|
return rvalue_reference_wrapper<T>(std::move(value));
|
|
}
|
|
template <typename T>
|
|
rvalue_reference_wrapper<T> rref(T&) noexcept = delete;
|
|
} // namespace folly
|