-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy path192.md
190 lines (150 loc) · 4.83 KB
/
192.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
<details open><summary>Info</summary><p>
* **Did you know about `std::expected` proposal for error handling?**
* http://wg21.link/p0323
</p></details><details open><summary>Example</summary><p>
```cpp
constexpr auto error(auto has_error) -> std::experimental::expected<bool, int> {
if (has_error) {
return std::experimental::unexpected{42};
} else {
return true;
}
}
int main() {
assert(error(false));
assert(error(false).value());
assert(not error(true).has_value());
assert(42 == error(true).error());
}
```
> https://godbolt.org/z/x1TKGv
</p></details><details open><summary>Puzzle</summary><p>
* **Can you implement a simplified version of `expected` proposal for error handling?**
```cpp
/*TODO - expected/unexpected*/
template<auto Error, class TValue, class TError>
constexpr auto handle_error(TValue value, TError error) -> expected<TValue, TError> {
if (Error) {
return unexpected{error};
} else {
return value;
}
}
int main() {
using namespace boost::ut;
using namespace std::string_literals;
"handle error"_test = [] {
constexpr auto error = true;
constexpr auto no_error = false;
should("be convertible to bool") = [] {
struct {} _;
expect(handle_error<no_error>(_, _) and
not handle_error< error>(_, _));
};
should("contain a value") = [] {
const auto handle_error = ::handle_error<no_error>(42, std::runtime_error{"error"s});
expect(handle_error and
handle_error.has_value() and
handle_error.value() == 42_i
);
};
should("contain an error") = [] {
const auto handle_error = ::handle_error<error>(42, std::runtime_error{"error"s});
expect(not handle_error and
not handle_error.has_value() and
"error"s == handle_error.error().what()
);
};
};
}
```
> https://godbolt.org/z/rf4sP5
</p></details><details><summary>Solutions</summary><p>
```cpp
struct error_tag {};
template <class TValue, class TError>
struct expected {
constexpr expected(TValue val) : value_{std::in_place_index<0>, val} {}
constexpr expected(TError err, error_tag) : value_{std::in_place_index<1>, err} {}
constexpr explicit operator bool() const { return has_value(); }
constexpr auto has_value() const { return value_.index() == 0; }
constexpr auto value() const { return std::get<0>(value_); }
constexpr auto error() const { return std::get<1>(value_); }
private:
std::variant<TValue, TError> value_;
};
template <class TError>
struct unexpected {
constexpr unexpected(TError error) : error_(error) {}
template <class TValue>
constexpr operator expected<TValue, TError>() { return expected<TValue, TError>{error_, error_tag{}}; }
private:
TError error_;
};
```
> https://godbolt.org/z/E6M5nr
```cpp
template<class TError>
struct unexpected {
unexpected(TError error) :error(error) {}
TError error;
};
template<class TValue, class TError>
struct expected {
expected(TValue value) : value_(value), has_value_(true) {}
expected(unexpected<TError> un) : has_value_(false), error_(un.error) {}
operator bool() const { return has_value_;}
TValue value() const { return value_; }
bool has_value() const { return has_value_; }
TError error() const { return error_.value(); }
private:
TValue value_;
bool has_value_;
std::optional<TError> error_;
};
```
> https://godbolt.org/z/4zbzTh
```cpp
template <typename TValue, typename TError>
struct expected {
constexpr explicit(false) expected(const TValue& value)
: val_or_err{std::in_place_index<VAL_INDEX>, value} {}
constexpr explicit(true) expected(const TError& error, [[maybe_unused]] const auto is_value)
: val_or_err{std::in_place_index<ERR_INDEX>, error} {}
constexpr operator bool() const { return has_value(); }
constexpr auto has_value() const { return val_or_err.index() == VAL_INDEX; }
constexpr auto value() const { return std::get<VAL_INDEX>(val_or_err); }
constexpr auto error() const { return std::get<ERR_INDEX>(val_or_err); }
static const auto VAL_INDEX = 0;
static const auto ERR_INDEX = 1;
std::variant<TValue, TError> val_or_err;
};
template <typename TError>
struct unexpected {
constexpr explicit(true) unexpected(const TError& e) : error{e} {}
template <typename TValue>
constexpr operator expected<TValue, TError>() const {
return expected<TValue, TError>{error, false};
}
TError error;
};
```
> https://godbolt.org/z/q69dK5
```cpp
template<typename E>
struct unexpected
{
unexpected(E e) : error(std::move(e)) { }
E error;
};
template<typename T, typename E>
struct expected : std::optional<T>
{
expected(T t) : std::optional<T>(std::move(t)) { }
expected(unexpected<E> u) : err(std::move(u.error)) {}
E error() const { return err.value(); }
std::optional<E> err;
};
```
> https://godbolt.org/z/EKxYhb
</p></details>