Add absl::optional_ref<T>

PiperOrigin-RevId: 872459397
Change-Id: Ib2a3265c46c1ceca31190f5d4722bde06b59eeb4
This commit is contained in:
Abseil Team
2026-02-19 10:26:39 -08:00
committed by Copybara-Service
parent 5088cf5194
commit a62029e346
5 changed files with 719 additions and 0 deletions

View File

@@ -453,6 +453,7 @@ set(ABSL_INTERNAL_DLL_FILES
"types/any.h"
"types/compare.h"
"types/optional.h"
"types/optional_ref.h"
"types/span.h"
"types/internal/span.h"
"types/variant.h"

View File

@@ -164,3 +164,29 @@ cc_test(
"@googletest//:gtest_main",
],
)
cc_library(
name = "optional_ref",
hdrs = ["optional_ref.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
"//absl/base:core_headers",
],
)
cc_test(
name = "optional_ref_test",
size = "small",
srcs = ["optional_ref_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":optional_ref",
"//absl/base:config",
"//absl/log",
"//absl/strings",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)

View File

@@ -154,6 +154,34 @@ absl_cc_test(
GTest::gmock_main
)
absl_cc_library(
NAME
internal_optional_ref
HDRS
"optional_ref.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::config
absl::core_headers
PUBLIC
)
absl_cc_test(
NAME
optional_ref_test
SRCS
"optional_ref_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::base
absl::config
absl::internal_optional_ref
absl::strings
GTest::gmock_main
)
# Deprecated empty library.
# Clients should remove this dependency.
absl_cc_library(

294
absl/types/optional_ref.h Normal file
View File

@@ -0,0 +1,294 @@
// Copyright 2026 The Abseil Authors.
//
// 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
//
// https://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.
//
// -----------------------------------------------------------------------------
// File: optional_ref.h
// -----------------------------------------------------------------------------
//
// `optional_ref<T>` provides a `std::optional`-like interface around `T*`.
// It is similar to C++26's `std::optional<T&>`, but with slight enhancements,
// such as the fact that it permits construction from rvalues. That is, it
// relaxes the std::reference_constructs_from_temporary constraint. Its intent
// is to make it easier for functions to accept nullable object addresses,
// regardless of whether or not they point to temporaries.
//
// It can be constructed in the following ways:
// * optional_ref<T> ref;
// * optional_ref<T> ref = std::nullopt;
// * T foo; optional_ref<T> ref = foo;
// * std::optional<T> foo; optional_ref<T> ref = foo;
// * T* foo = ...; optional_ref<T> ref = foo;
// * optional_ref<T> foo; optional_ref<const T> ref = foo;
//
// Since it is trivially copyable and destructible, it should be passed by
// value.
//
// Other properties:
// * Assignment is not allowed. Example:
// optional_ref<int> ref;
// // Compile error.
// ref = 2;
//
// * operator bool() is intentionally not defined, as it would be error prone
// for optional_ref<bool>.
//
// Example usage, assuming some type `T` that is expensive to copy:
// void ProcessT(optional_ref<const T> input) {
// if (!input.has_value()) {
// // Handle empty case.
// return;
// }
// const T& val = *input;
// // Do something with val.
// }
//
// ProcessT(std::nullopt);
// ProcessT(BuildT());
#ifndef ABSL_TYPES_OPTIONAL_REF_H_
#define ABSL_TYPES_OPTIONAL_REF_H_
#include <cstddef>
#include <memory>
#include <optional>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
template <typename T>
class optional_ref {
template <typename U>
using EnableIfConvertibleFrom =
std::enable_if_t<std::is_convertible_v<U*, T*>>;
public:
using value_type = T;
constexpr optional_ref() : ptr_(nullptr) {}
constexpr optional_ref( // NOLINT(google-explicit-constructor)
std::nullopt_t)
: ptr_(nullptr) {}
// Constructor given a concrete value.
constexpr optional_ref( // NOLINT(google-explicit-constructor)
T& input ABSL_ATTRIBUTE_LIFETIME_BOUND)
: ptr_(std::addressof(input)) {}
// Constructors given an existing std::optional value.
// Templated on the input optional's type to avoid creating a temporary.
template <typename U, typename = EnableIfConvertibleFrom<const U>>
constexpr optional_ref( // NOLINT(google-explicit-constructor)
const std::optional<U>& input ABSL_ATTRIBUTE_LIFETIME_BOUND)
: ptr_(input.has_value() ? std::addressof(*input) : nullptr) {}
template <typename U, typename = EnableIfConvertibleFrom<U>>
constexpr optional_ref( // NOLINT(google-explicit-constructor)
std::optional<U>& input ABSL_ATTRIBUTE_LIFETIME_BOUND)
: ptr_(input.has_value() ? std::addressof(*input) : nullptr) {}
// Constructor given a T*, where nullptr indicates empty/absent.
constexpr optional_ref( // NOLINT(google-explicit-constructor)
T* input ABSL_ATTRIBUTE_LIFETIME_BOUND)
: ptr_(input) {}
// Don't allow naked nullptr as input, as this creates confusion in the case
// of optional_ref<T*>. Use std::nullopt instead to create an empty
// optional_ref.
constexpr optional_ref( // NOLINT(google-explicit-constructor)
std::nullptr_t) = delete;
// Copying is allowed.
optional_ref(const optional_ref<T>&) = default;
// Assignment is not allowed.
optional_ref<T>& operator=(const optional_ref<T>&) = delete;
// Conversion from optional_ref<U> is allowed iff U* is convertible to T*.
// (Note this also allows non-const to const conversions.)
template <typename U, typename = EnableIfConvertibleFrom<U>>
constexpr optional_ref( // NOLINT(google-explicit-constructor)
optional_ref<U> input)
: ptr_(input.as_pointer()) {}
// Determines whether the `optional_ref` contains a value. Returns `false` if
// and only if `*this` is empty.
constexpr bool has_value() const { return ptr_ != nullptr; }
// Returns a reference to an `optional_ref`s underlying value. The constness
// and lvalue/rvalue-ness of the `optional_ref` is preserved to the view of
// the `T` sub-object. Throws the same error as `std::optional`'s `value()`
// when the `optional_ref` is empty.
constexpr T& value() const {
return ABSL_PREDICT_TRUE(ptr_ != nullptr)
? *ptr_
// Replicate the same error logic as in `std::optional`'s
// `value()`. It either throws an exception or aborts the
// program. We intentionally ignore the return value of
// the constructed optional's value as we only need to run
// the code for error checking.
: ((void)std::optional<T>().value(), *ptr_);
}
// Returns the value iff *this has a value, otherwise returns `default_value`.
template <typename U>
constexpr T value_or(U&& default_value) const {
// Instantiate std::optional<T>::value_or(U) to trigger its static_asserts.
if (false) {
// We use `std::add_const_t` here since just using `const` makes MSVC
// complain about the syntax.
(void)std::add_const_t<std::optional<T>>{}.value_or(
std::forward<U>(default_value));
}
return ptr_ != nullptr ? *ptr_
: static_cast<T>(std::forward<U>(default_value));
}
// Accesses the underlying `T` value of an `optional_ref`. If the
// `optional_ref` is empty, behavior is undefined.
constexpr T& operator*() const {
ABSL_HARDENING_ASSERT(ptr_ != nullptr);
return *ptr_;
}
constexpr T* operator->() const {
ABSL_HARDENING_ASSERT(ptr_ != nullptr);
return ptr_;
}
// Convenience function to represent the `optional_ref` as a `T*` pointer.
constexpr T* as_pointer() const { return ptr_; }
// Convenience function to represent the `optional_ref` as an `optional`,
// which incurs a copy when the `optional_ref` is non-empty. The template type
// allows for implicit type conversion; example:
// optional_ref<std::string> a = ...;
// std::optional<std::string_view> b = a.as_optional<std::string_view>();
template <typename U = std::decay_t<T>>
constexpr std::optional<U> as_optional() const {
if (ptr_ == nullptr) return std::nullopt;
return *ptr_;
}
private:
T* const ptr_;
// T constraint checks. You can't have an optional of nullopt_t or
// in_place_t.
static_assert(!std::is_same_v<std::nullopt_t, std::remove_cv_t<T>>,
"optional_ref<nullopt_t> is not allowed.");
static_assert(!std::is_same_v<std::in_place_t, std::remove_cv_t<T>>,
"optional_ref<in_place_t> is not allowed.");
};
// Template type deduction guides:
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>;
namespace optional_ref_internal {
// This is a C++-11 compatible version of std::equality_comparable_with that
// only requires `t == u` is a valid boolean expression.
//
// We still need this for a couple reasons:
// - As of 2026-02-13, Abseil supports C++17.
// - Even for targets that are built with the default toolchain, using
// std::equality_comparable_with gives us an error due to mutual recursion
// between its definition and our definition of operator==.
//
template <typename T, typename U>
using enable_if_equality_comparable_t = std::enable_if_t<std::is_convertible_v<
decltype(std::declval<T>() == std::declval<U>()), bool>>;
} // namespace optional_ref_internal
// Compare an optional referenced value to std::nullopt.
template <typename T>
constexpr bool operator==(optional_ref<T> a, std::nullopt_t) {
return !a.has_value();
}
template <typename T>
constexpr bool operator==(std::nullopt_t, optional_ref<T> b) {
return !b.has_value();
}
template <typename T>
constexpr bool operator!=(optional_ref<T> a, std::nullopt_t) {
return a.has_value();
}
template <typename T>
constexpr bool operator!=(std::nullopt_t, optional_ref<T> b) {
return b.has_value();
}
// Compare two optional referenced values. Note, this does not test that the
// contained `ptr_`s are equal. If the caller wants "shallow" reference equality
// semantics, they should use `as_pointer()` explicitly.
template <typename T, typename U>
constexpr bool operator==(optional_ref<T> a, optional_ref<U> b) {
return a.has_value() ? *a == b : !b.has_value();
}
// Compare an optional referenced value to a non-optional value.
template <
typename T, typename U,
typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
constexpr bool operator==(const T& a, optional_ref<U> b) {
return b.has_value() && a == *b;
}
template <
typename T, typename U,
typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
constexpr bool operator==(optional_ref<T> a, const U& b) {
return b == a;
}
// Inequality operators, as above.
template <typename T, typename U>
constexpr bool operator!=(optional_ref<T> a, optional_ref<U> b) {
return !(a == b);
}
template <
typename T, typename U,
typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
constexpr bool operator!=(optional_ref<T> a, const U& b) {
return !(a == b);
}
template <
typename T, typename U,
typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
constexpr bool operator!=(const T& a, optional_ref<U> b) {
return !(a == b);
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TYPES_OPTIONAL_REF_H_

View File

@@ -0,0 +1,370 @@
// Copyright 2026 The Abseil Authors.
//
// 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
//
// https://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.
#include "absl/types/optional_ref.h"
#include <cstddef>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace {
using ::testing::Optional;
using ::testing::Pointee;
TEST(OptionalRefTest, SimpleType) {
int val = 5;
optional_ref<int> ref = optional_ref(val);
optional_ref<int> empty_ref = std::nullopt;
EXPECT_THAT(ref, Optional(5));
EXPECT_TRUE(ref.has_value());
EXPECT_EQ(*ref, val);
EXPECT_EQ(ref.value(), val);
EXPECT_EQ(ref, ref);
EXPECT_EQ(ref, val);
EXPECT_EQ(val, ref);
EXPECT_NE(ref, empty_ref);
EXPECT_NE(empty_ref, ref);
}
TEST(OptionalRefTest, SimpleConstType) {
const int val = 5;
optional_ref<const int> ref = optional_ref(val);
EXPECT_THAT(ref, Optional(5));
}
TEST(OptionalRefTest, DefaultConstructed) {
optional_ref<int> ref;
EXPECT_EQ(ref, std::nullopt);
EXPECT_EQ(std::nullopt, ref);
}
TEST(OptionalRefTest, EmptyOptional) {
auto ref = optional_ref<int>(std::nullopt);
EXPECT_EQ(ref, std::nullopt);
EXPECT_EQ(std::nullopt, ref);
}
TEST(OptionalRefTest, OptionalType) {
const std::optional<int> val = 5;
optional_ref<const int> ref = val;
EXPECT_THAT(ref, Optional(5));
EXPECT_EQ(ref.as_pointer(), &*val);
const std::optional<int> empty;
optional_ref<const int> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
// Cannot make non-const reference to const optional.
static_assert(
!std::is_convertible_v<const std::optional<int>&, optional_ref<int>>);
}
TEST(OptionalRefTest, NonConstOptionalType) {
std::optional<int> val = 5;
optional_ref<int> ref = val;
EXPECT_THAT(ref, Optional(5));
EXPECT_EQ(ref.as_pointer(), &*val);
std::optional<int> empty;
optional_ref<int> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
}
TEST(OptionalRefTest, NonConstOptionalTypeToConstRef) {
std::optional<int> val = 5;
optional_ref<const int> ref = val;
EXPECT_THAT(ref, Optional(5));
EXPECT_EQ(ref.as_pointer(), &*val);
std::optional<int> empty;
optional_ref<const int> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
}
TEST(OptionalRefTest, NonConstOptionalWithConstValueType) {
std::optional<const int> val = 5;
optional_ref<const int> ref = val;
EXPECT_THAT(ref, Optional(5));
EXPECT_EQ(ref.as_pointer(), &*val);
std::optional<const int> empty;
optional_ref<const int> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
// Not possible to convert to non-const reference.
static_assert(
!std::is_convertible_v<std::optional<const int>&, optional_ref<int>>);
}
class TestInterface {};
class TestDerivedClass : public TestInterface {};
TEST(OptionalRefTest, BaseDerivedConvertibleOptionalType) {
const std::optional<TestDerivedClass> dc = TestDerivedClass{};
optional_ref<const TestInterface> ref = dc;
EXPECT_NE(ref, std::nullopt);
EXPECT_EQ(ref.as_pointer(), &*dc);
const std::optional<TestDerivedClass> empty;
optional_ref<const TestInterface> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<const std::optional<TestInterface>&,
optional_ref<const TestDerivedClass>>);
static_assert(!std::is_convertible_v<const std::optional<TestDerivedClass>&,
optional_ref<TestInterface>>);
}
TEST(OptionalRefTest, NonConstBaseDerivedConvertibleOptionalType) {
std::optional<TestDerivedClass> dc = TestDerivedClass{};
optional_ref<TestInterface> ref = dc;
EXPECT_NE(ref, std::nullopt);
EXPECT_EQ(ref.as_pointer(), &*dc);
std::optional<TestDerivedClass> empty;
optional_ref<TestInterface> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<std::optional<TestInterface>&,
optional_ref<TestDerivedClass>>);
}
TEST(OptionalRefTest, NonConstBaseDerivedConvertibleOptionalTypeToConstRef) {
std::optional<TestDerivedClass> dc = TestDerivedClass{};
optional_ref<const TestInterface> ref = dc;
EXPECT_NE(ref, std::nullopt);
EXPECT_EQ(ref.as_pointer(), &*dc);
std::optional<TestDerivedClass> empty;
optional_ref<const TestInterface> empty_ref = empty;
EXPECT_EQ(empty_ref, std::nullopt);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<std::optional<TestInterface>&,
optional_ref<const TestDerivedClass>>);
static_assert(!std::is_convertible_v<const std::optional<TestInterface>&,
optional_ref<const TestDerivedClass>>);
}
TEST(OptionalRefTest, PointerCtor) {
int val = 5;
optional_ref<const int> ref = &val;
EXPECT_THAT(ref, Optional(5));
auto auto_ref = optional_ref(&val);
static_assert(std::is_same_v<decltype(auto_ref), optional_ref<int>>,
"optional_ref(T*) should deduce to optional_ref<T>.");
EXPECT_THAT(auto_ref, Optional(5));
int* foo = nullptr;
optional_ref<const int> empty_ref = foo;
EXPECT_EQ(empty_ref, std::nullopt);
optional_ref<int*> ptr_ref = foo;
EXPECT_THAT(ptr_ref, Optional(nullptr));
static_assert(
!std::is_constructible_v<optional_ref<int*>, std::nullptr_t>,
"optional_ref should not be constructible with std::nullptr_t.");
// Pointer polymorphism works.
TestDerivedClass dc;
optional_ref<const TestInterface> dc_ref = &dc;
EXPECT_NE(dc_ref, std::nullopt);
}
TEST(OptionalRefTest, ValueDeathWhenEmpty) {
optional_ref<int> ref;
#ifdef ABSL_HAVE_EXCEPTIONS
EXPECT_THROW(ref.value(), std::bad_optional_access);
#else
EXPECT_DEATH_IF_SUPPORTED(ref.value(), "");
#endif
}
TEST(OptionalRefTest, ImplicitCtor) {
const int val = 5;
optional_ref<const int> ref = val;
EXPECT_THAT(ref, Optional(5));
}
TEST(OptionalRefTest, DoesNotCopy) {
// Non-copyable type.
auto val = std::make_unique<int>(5);
optional_ref<std::unique_ptr<int>> ref = optional_ref(val);
EXPECT_THAT(ref, Optional(Pointee(5)));
}
TEST(OptionalRefTest, DoesNotCopyConst) {
// Non-copyable type.
const auto val = std::make_unique<int>(5);
optional_ref<const std::unique_ptr<int>> ref = optional_ref(val);
EXPECT_THAT(ref, Optional(Pointee(5)));
}
TEST(OptionalRefTest, RefCopyable) {
auto val = std::make_unique<int>(5);
optional_ref<std::unique_ptr<int>> ref = optional_ref(val);
optional_ref<std::unique_ptr<int>> copy = ref;
EXPECT_THAT(copy, Optional(Pointee(5)));
}
TEST(OptionalRefTest, ConstConvertible) {
auto val = std::make_unique<int>(5);
optional_ref<std::unique_ptr<int>> ref = optional_ref(val);
optional_ref<const std::unique_ptr<int>> converted = ref;
EXPECT_THAT(converted, Optional(Pointee(5)));
EXPECT_EQ(converted.as_pointer(), &val);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<optional_ref<const std::unique_ptr<int>>,
optional_ref<std::unique_ptr<int>>>);
}
TEST(OptionalRefTest, BaseDerivedConvertible) {
TestDerivedClass dc;
optional_ref<TestDerivedClass> dc_ref = dc;
optional_ref<TestInterface> converted = dc_ref;
EXPECT_NE(converted, std::nullopt);
EXPECT_EQ(converted.as_pointer(), &dc);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<optional_ref<TestInterface>,
optional_ref<TestDerivedClass>>);
}
TEST(OptionalRefTest, BaseDerivedConstConvertible) {
TestDerivedClass dc;
optional_ref<TestDerivedClass> dc_ref = dc;
optional_ref<const TestInterface> converted = dc_ref;
EXPECT_NE(converted, std::nullopt);
EXPECT_EQ(converted.as_pointer(), &dc);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<optional_ref<const TestInterface>,
optional_ref<TestDerivedClass>>);
static_assert(!std::is_convertible_v<optional_ref<const TestDerivedClass>,
optional_ref<TestInterface>>);
}
TEST(OptionalRefTest, BaseDerivedBothConstConvertible) {
TestDerivedClass dc;
optional_ref<const TestDerivedClass> dc_ref = dc;
optional_ref<const TestInterface> converted = dc_ref;
EXPECT_NE(converted, std::nullopt);
EXPECT_EQ(converted.as_pointer(), &dc);
// Not possible in the other direction.
static_assert(!std::is_convertible_v<optional_ref<const TestInterface>,
optional_ref<const TestDerivedClass>>);
}
TEST(OptionalRefTest, TriviallyCopyable) {
static_assert(
std::is_trivially_copyable_v<optional_ref<std::unique_ptr<int>>>);
}
TEST(OptionalRefTest, TriviallyDestructible) {
static_assert(
std::is_trivially_destructible_v<optional_ref<std::unique_ptr<int>>>);
}
TEST(OptionalRefTest, RefNotAssignable) {
static_assert(!std::is_copy_assignable_v<optional_ref<int>>);
static_assert(!std::is_move_assignable_v<optional_ref<int>>);
}
struct TestStructWithCopy {
TestStructWithCopy() = default;
TestStructWithCopy(TestStructWithCopy&&) {
LOG(FATAL) << "Move constructor should not be called";
}
TestStructWithCopy(const TestStructWithCopy&) {
LOG(FATAL) << "Copy constructor should not be called";
}
TestStructWithCopy& operator=(const TestStructWithCopy&) {
LOG(FATAL) << "Assign operator should not be called";
}
};
TEST(OptionalRefTest, DoesNotCopyUsingFatalCopyAssignOps) {
TestStructWithCopy val;
optional_ref<TestStructWithCopy> ref = optional_ref(val);
EXPECT_NE(ref, std::nullopt);
EXPECT_NE(optional_ref(TestStructWithCopy{}), std::nullopt);
}
std::string AddExclamation(optional_ref<const std::string> input) {
if (!input.has_value()) {
return "";
}
return absl::StrCat(*input, "!");
}
TEST(OptionalRefTest, RefAsFunctionParameter) {
EXPECT_EQ(AddExclamation(std::nullopt), "");
EXPECT_EQ(AddExclamation(std::string("abc")), "abc!");
std::string s = "def";
EXPECT_EQ(AddExclamation(s), "def!");
EXPECT_EQ(AddExclamation(std::make_optional<std::string>(s)), "def!");
}
TEST(OptionalRefTest, ValueOrWhenHasValue) {
std::optional<int> val = 5;
EXPECT_EQ(optional_ref(val).value_or(2), 5);
}
TEST(OptionalRefTest, ValueOrWhenEmpty) {
std::optional<int> val = std::nullopt;
EXPECT_EQ(optional_ref(val).value_or(2), 2);
}
TEST(OptionalRefTest, AsOptional) {
EXPECT_EQ(optional_ref<int>().as_optional(), std::nullopt);
std::string val = "foo";
optional_ref<const std::string> ref = val;
static_assert(
std::is_same_v<decltype(ref.as_optional()), std::optional<std::string>>,
"The type parameter of optional_ref should decay by default for the "
"return type in as_optional().");
std::optional<std::string> opt_string = ref.as_optional();
EXPECT_THAT(opt_string, Optional(val));
std::optional<std::string_view> opt_view =
ref.as_optional<std::string_view>();
EXPECT_THAT(opt_view, Optional(val));
}
TEST(OptionalRefTest, Constexpr) {
static constexpr int foo = 123;
constexpr optional_ref<const int> ref(foo);
static_assert(ref.has_value() && *ref == foo && ref.value() == foo, "");
}
} // namespace
ABSL_NAMESPACE_END
} // namespace absl