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