Skip to content

Commit 3628c58

Browse files
committed
improve Result error type constraints
1 parent 7d4eea4 commit 3628c58

File tree

1 file changed

+41
-46
lines changed

1 file changed

+41
-46
lines changed

include/common/result.hpp

Lines changed: 41 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class SentinelValue<T> {
5353
// This means that Result will always contain an expected value.
5454
// Therefore, if the user does not check if a function returned an error, an exception will NOT be
5555
// thrown, and therefore the thread won't crash.
56+
// Constraint: requires at least 1 possible Error type
57+
// Constraint: Error types must inherit from ResultError
5658
template<typename T, typename... Errs>
5759
requires(sizeof...(Errs) > 0) && (std::derived_from<Errs, ResultError> && ...)
5860
class Result {
@@ -67,56 +69,45 @@ class Result {
6769

6870
// Construct a Result with a value and an error value.
6971
// Constraint: type T can be constructed from type U
70-
// Constraint: some type in Errs can be constructed from type E
72+
// Constraint: E in Errs
7173
template<typename U, typename E>
72-
requires std::constructible_from<T, U> && (std::constructible_from<E, Errs> || ...)
74+
requires std::constructible_from<T, U> && (std::same_as<std::remove_cvref<E>, Errs> || ...)
7375
constexpr Result(U&& value, E&& error)
7476
: value(std::forward<U>(value)),
7577
error(std::forward<E>(error)) {}
7678

7779
// Construct a Result with an error, initializing the normal value to its sentinel value.
7880
// Constraint: type T has a sentinel value
79-
// Constraint: some type in Errs can be constructed from type U
80-
// Constraint: type U can't be implicitly converted to type T
81-
template<typename U>
82-
requires Sentinel<T> && (std::constructible_from<U, Errs> || ...)
83-
&& (!std::convertible_to<U, T>)
84-
constexpr Result(U&& error)
85-
: error(std::forward<U>(error)),
86-
value(sentinel_v<T>) {}
87-
88-
// Construct a Result with an error, initializing the normal value to its sentinel value.
89-
// Constraint: type T has a sentinel value
90-
// Constraint: some type in Errs can be constructed from type U
91-
template<typename U>
92-
requires Sentinel<U> && (std::constructible_from<U, Errs> || ...)
93-
explicit constexpr Result<U>(U&& error)
94-
: error(std::forward<U>(error)),
81+
// Constraint: E in Errs
82+
template<typename E>
83+
requires Sentinel<T> && (std::same_as<std::remove_cvref<E>, Errs> || ...)
84+
constexpr Result(E&& error)
85+
: error(std::forward<E>(error)),
9586
value(sentinel_v<T>) {}
9687

9788
// Get the given error type, if it exists
98-
// Constraint: some type Errs can be constructed from type U
99-
template<typename U>
100-
requires(std::same_as<U, Errs> || ...)
101-
constexpr std::optional<U> get() const& {
89+
// Constraint: E in Errs
90+
template<typename E>
91+
requires(std::same_as<E, Errs> || ...)
92+
constexpr std::optional<E> get() const& {
10293
if (std::holds_alternative<std::monostate>(error)) {
10394
return std::nullopt;
10495
} else {
105-
return std::get<U>(error);
96+
return std::get<E>(error);
10697
}
107-
};
98+
}
10899

109100
// Get the given error type, if it exists
110-
// Constraint: some type Errs can be constructed from type U
111-
template<typename U>
112-
requires(std::same_as<U, Errs> || ...)
113-
constexpr std::optional<U> get() && {
101+
// Constraint: E in Errs
102+
template<typename E>
103+
requires(std::same_as<E, Errs> || ...)
104+
constexpr std::optional<E> get() && {
114105
if (std::holds_alternative<std::monostate>(error)) {
115106
return std::nullopt;
116107
} else {
117-
return std::move(std::get<U>(error));
108+
return std::move(std::get<E>(error));
118109
}
119-
};
110+
}
120111

121112
// get the normal value
122113
template<typename U = T>
@@ -155,43 +146,47 @@ class Result {
155146
T value;
156147
};
157148

149+
// Result specialization for a value of type void, which would otherwise be impossible.
150+
// This specialization simply does not hold a "normal" value
151+
// Constraint: requires at least 1 possible Error type
152+
// Constraint: Error types must inherit from ResultError
158153
template<typename... Errs>
159154
requires(sizeof...(Errs) > 0) && (std::derived_from<Errs, ResultError> && ...)
160155
class Result<void, Errs...> {
161156
public:
162157
// construct with an error value
163-
template<typename U>
164-
requires(std::constructible_from<Errs, U> || ...)
165-
constexpr Result(U&& error)
166-
: error(std::forward<U>(error)) {}
158+
template<typename E>
159+
requires(std::same_as<std::remove_cvref<E>, Errs> || ...)
160+
constexpr Result(E&& error)
161+
: error(std::forward<E>(error)) {}
167162

168163
// construct with no error value
169164
constexpr Result()
170165
: error(std::monostate()) {}
171166

172167
// Get the given error type, if it exists
173-
// Constraint: some type Errs can be constructed from type U
174-
template<typename U>
175-
requires(std::same_as<U, Errs> || ...)
176-
constexpr std::optional<U> get() const& {
168+
// Constraint: E in Errs
169+
template<typename E>
170+
requires(std::same_as<E, Errs> || ...)
171+
constexpr std::optional<E> get() const& {
177172
if (std::holds_alternative<std::monostate>(error)) {
178173
return std::nullopt;
179174
} else {
180-
return std::get<U>(error);
175+
return std::get<E>(error);
181176
}
182-
};
177+
}
183178

184179
// Get the given error type, if it exists
185-
// Constraint: some type Errs can be constructed from type U
186-
template<typename U>
187-
requires(std::same_as<U, Errs> || ...)
188-
constexpr std::optional<U> get() && {
180+
// Constraint: E in Errs
181+
template<typename E>
182+
requires(std::same_as<E, Errs> || ...)
183+
constexpr std::optional<E> get() && {
189184
if (std::holds_alternative<std::monostate>(error)) {
190185
return std::nullopt;
191186
} else {
192-
return std::move(std::get<U>(error));
187+
return std::move(std::get<E>(error));
193188
}
194-
};
189+
}
195190

196191
std::variant<std::monostate, Errs...> error;
197192
};

0 commit comments

Comments
 (0)