// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_TYPES_OPTIONAL_REF_H_ #define BASE_TYPES_OPTIONAL_REF_H_ #include <memory> #include <optional> #include <type_traits> #include "base/check.h" #include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/base/attributes.h" namespace base { // `optional_ref<T>` is similar to `std::optional<T>`, except it does not own // the underlying value. // // When passing an optional parameter, prefer `optional_ref` to `const // std::optional<T>&` as the latter often results in hidden copies due to // implicit conversions, e.g. given the function: // // void TakesOptionalString(const std::optional<std::string>& str); // // And a call to that looks like: // // std::string s = "Hello world!"; // TakesOptionalString(s); // // This copies `s` into a temporary `std::optional<std::string>` in order to // call `TakesOptionalString()`. // // The C++ style guide recommends using `const T*` instead of `const // std::optional<T>&` when `T` would normally be passed by reference. However // `const T*` is not always a good substitute because: // // - `const T*` disallows the use of temporaries, since it is not possible to // take the address of a temporary. // - additional boilerplate (e.g. `OptionalToPtr`) is required to pass an // `std::optional<T>` to a `const T*` function parameter. // // Like `span<T>`, mutability of `optional_ref<T>` is controlled by the template // argument `T`; e.g. `optional_ref<const int>` only allows const access to the // referenced `int` value. // // Thus, `optional_ref<const T>` can be constructed from: // - `std::nullopt` // - `const T*` or `T*` // - `const T&` or `T&` // ` `const std::optional<T>&` or `std::optional<T>&` // // While `optional_ref<T>` can only be constructed from: // - `std::nullopt` // - `T*` // - `T&` // - `std::optional<T>&` // // Implicit conversions are disallowed, e.g. this will not compile: // // [](base::optional_ref<std::string> s) {}("Hello world!"); // // This restriction may be relaxed in the future if it proves too onerous. // // `optional_ref<T>` is lightweight and should be passed by value. It is copy // constructible but not copy assignable, to reduce the risk of lifetime bugs. template <typename T> class optional_ref { … }; template <typename T> optional_ref(const T&) -> optional_ref<const T>; template <typename T> optional_ref(T&) -> optional_ref<T>; template <typename T> optional_ref(const std::optional<T>&) -> optional_ref<const T>; template <typename T> optional_ref(std::optional<T>&) -> optional_ref<T>; template <typename T> optional_ref(T*) -> optional_ref<T>; template <typename T> constexpr bool operator==(std::nullopt_t, optional_ref<T> x) { … } template <typename T> constexpr bool operator==(optional_ref<T> x, std::nullopt_t) { … } } // namespace base #endif // BASE_TYPES_OPTIONAL_REF_H_