userver: userver/utils/required.hpp Source File
Loading...
Searching...
No Matches
required.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/required.hpp
4/// @brief @copybrief utils::Required
5
6#include <concepts>
7#include <memory>
8#include <string_view>
9#include <type_traits>
10#include <utility>
11
12#include <userver/compiler/impl/lifetime.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace utils {
17
18/// @brief A wrapper that holds a value of type `T` and has no default
19/// constructor, forcing explicit initialization.
20///
21/// Unlike `std::optional`, `Required` is always engaged after construction.
22/// It is useful for struct fields that must be explicitly set.
23///
24/// ## Example usage
25///
26/// @snippet utils/required_test.cpp sample
27///
28/// @snippet utils/required_test.cpp sample usage
29template <typename T>
30class Required final {
31public:
32 Required() = delete;
33
34 /// @brief Construct `T` from a value (conditionally explicit).
35 template <typename U>
36 requires(!std::same_as<std::decay_t<U>, Required> && std::constructible_from<T, U &&>)
37 constexpr explicit(!std::convertible_to<U&&, T>) Required(U&& value)
38 : value_(std::forward<U>(value))
39 {}
40
41 /// @brief Emplace-construct `T` from `args`.
42 template <typename... Args>
43 requires(sizeof...(Args) >= 2 && std::constructible_from<T, Args && ...>)
44 constexpr explicit Required(Args&&... args)
45 : value_(std::forward<Args>(args)...)
46 {}
47
48 Required(const Required&) = default;
49 Required& operator=(const Required&) = default;
50 Required(Required&&) = default;
51 Required& operator=(Required&&) = default;
52
53 /// @brief Access the contained value.
54 constexpr T& operator*() & noexcept USERVER_IMPL_LIFETIME_BOUND { return value_; }
55
56 /// @overload
57 constexpr const T& operator*() const& noexcept USERVER_IMPL_LIFETIME_BOUND { return value_; }
58
59 /// @overload
60 constexpr T&& operator*() && noexcept { return std::move(value_); }
61
62 /// @brief Access members of the contained value.
63 constexpr T* operator->() noexcept USERVER_IMPL_LIFETIME_BOUND { return std::addressof(value_); }
64
65 /// @overload
66 constexpr const T* operator->() const noexcept USERVER_IMPL_LIFETIME_BOUND { return std::addressof(value_); }
67
68 /// @brief Implicit conversion to `T&`.
69 constexpr /*implicit*/ operator T&() & noexcept USERVER_IMPL_LIFETIME_BOUND { return value_; }
70
71 /// @brief Implicit conversion to `const T&`.
72 constexpr /*implicit*/ operator const T&() const& noexcept USERVER_IMPL_LIFETIME_BOUND { return value_; }
73
74 /// @brief Implicit conversion to any type that `T` is implicitly convertible to (by value).
75 template <typename U>
76 requires(!std::same_as<U, T> && !std::is_reference_v<U> && std::convertible_to<const T&, U>)
77 constexpr /*implicit*/ operator U() const {
78 return value_;
79 }
80
81private:
82 T value_;
83};
84
85/// @brief Convert `Required<T>` to `std::string_view` via ADL-found `ToStringView` on the inner value.
86///
87/// Participates in overload resolution only when `ToStringView(*req)` is valid.
88template <typename T>
89requires requires(const T& v) {
90 {
91 ToStringView(v)
92 } -> std::same_as<std::string_view>;
93}
94std::string_view ToStringView(const Required<T>& req) {
95 return ToStringView(*req);
96}
97
98} // namespace utils
99
100USERVER_NAMESPACE_END