Skip to content

Commit 75b6265

Browse files
committed
wording: store the error as unexpected<E> in the primary and void specs
The step-1 relaxation lets expected<T, E> and expected<void, E> take an lvalue-reference E, but their ratified exposition stores the error as a bare union member E unex, which is ill-formed for E& (same as-if defect just fixed in [expected.ref]). Change both union members to unexpected<E> and route error access through unex.error(). The edit is surgical: construct_at(addressof(unex), ...), reinit-expected, swap(unex, rhs.unex), and the "direct-non-list-initializes unex with the error" construction prose all operate correctly on unexpected<E> unchanged. Only the four error() returns (-> unex.error()), the same-state assignment lines (unex = rhs.unex; and unex = unexpected<E>(...e.error())), and the primary swap's temporary (E tmp -> unexpected<E> tmp) change. unexpected<E> assignment gives rebind for reference E and assign-through for object E, which is exactly the intended semantics. Left as a follow-up (equivalent, not incorrect): the swap noexcept specification still tests is_nothrow_swappable_v<E>, which is over-conservative for a reference E (the pointer swap is always noexcept). Verified: build clean at 93 pages; stripped diff vs expected-base.tex changes exactly the 16 intended lines (13 storage + 3 relaxation), no churn; bad_expected_access and unexpected keep E unex (a reference class member, not a union member, is legal).
1 parent d740a83 commit 75b6265

1 file changed

Lines changed: 13 additions & 13 deletions

File tree

papers/expected-new.tex

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@
612612
bool @\exposid{has_val}@; // \expos
613613
union {
614614
remove_cv_t<T> @\exposid{val}@; // \expos
615-
E @\exposid{unex}@; // \expos
615+
unexpected<E> @\exposid{unex}@; // \expos
616616
};
617617
};
618618
}
@@ -1062,7 +1062,7 @@
10621062
@\exposid{reinit-expected}@(@\exposid{val}@, @\exposid{unex}@, *rhs)
10631063
\end{codeblock}
10641064
\item
1065-
Otherwise, equivalent to \tcode{\exposid{unex} = rhs.error()}.
1065+
Otherwise, equivalent to \tcode{\exposid{unex} = rhs.\exposid{unex}}.
10661066
\end{itemize}
10671067
Then, if no exception was thrown,
10681068
equivalent to: \tcode{\exposid{has_val} = rhs.has_value(); return *this;}
@@ -1139,7 +1139,7 @@
11391139
@\exposid{reinit-expected}@(@\exposid{val}@, @\exposid{unex}@, std::move(*rhs))
11401140
\end{codeblock}
11411141
\item
1142-
Otherwise, equivalent to \tcode{\exposid{unex} = std::move(rhs.error())}.
1142+
Otherwise, equivalent to \tcode{\exposid{unex} = std::move(rhs.\exposid{unex})}.
11431143
\end{itemize}
11441144
Then, if no exception was thrown,
11451145
equivalent to: \tcode{has_val = rhs.has_value(); return *this;}
@@ -1247,7 +1247,7 @@
12471247
\end{codeblock}
12481248
\item
12491249
Otherwise, equivalent to:
1250-
\tcode{\exposid{unex} = std::forward<GF>(e.error());}
1250+
\tcode{\exposid{unex} = unexpected<E>(std::forward<GF>(e.error()));}
12511251
\end{itemize}
12521252

12531253
\pnum
@@ -1349,7 +1349,7 @@
13491349
\tcode{this->has_value()} is \tcode{true}, equivalent to:
13501350
\begin{codeblock}
13511351
if constexpr (is_nothrow_move_constructible_v<E>) {
1352-
E tmp(std::move(rhs.@\exposid{unex}@));
1352+
unexpected<E> tmp(std::move(rhs.@\exposid{unex}@));
13531353
destroy_at(addressof(rhs.@\exposid{unex}@));
13541354
try {
13551355
construct_at(addressof(rhs.@\exposid{val}@), std::move(@\exposid{val}@));
@@ -1517,7 +1517,7 @@
15171517

15181518
\pnum
15191519
\returns
1520-
\exposid{unex}.
1520+
\tcode{\exposid{unex}.error()}.
15211521
\end{itemdescr}
15221522

15231523
\indexlibrarymember{error}{expected}%
@@ -1533,7 +1533,7 @@
15331533

15341534
\pnum
15351535
\returns
1536-
\tcode{std::move(\exposid{unex})}.
1536+
\tcode{std::move(\exposid{unex}).error()}.
15371537
\end{itemdescr}
15381538

15391539
\indexlibrarymember{value_or}{expected}%
@@ -2025,7 +2025,7 @@
20252025
private:
20262026
bool @\exposid{has_val}@; // \expos
20272027
union {
2028-
E @\exposid{unex}@; // \expos
2028+
unexpected<E> @\exposid{unex}@; // \expos
20292029
};
20302030
};
20312031
\end{codeblock}
@@ -2300,7 +2300,7 @@
23002300
Otherwise, if \tcode{rhs.has_value()} is \tcode{true},
23012301
destroys \exposid{unex} and sets \exposid{has_val} to \tcode{true}.
23022302
\item
2303-
Otherwise, equivalent to \tcode{\exposid{unex} = rhs.error()}.
2303+
Otherwise, equivalent to \tcode{\exposid{unex} = rhs.\exposid{unex}}.
23042304
\end{itemize}
23052305

23062306
\pnum
@@ -2347,7 +2347,7 @@
23472347
Otherwise, if \tcode{rhs.has_value()} is \tcode{true},
23482348
destroys \exposid{unex} and sets \exposid{has_val} to \tcode{true}.
23492349
\item
2350-
Otherwise, equivalent to \tcode{\exposid{unex} = std::move(rhs.error())}.
2350+
Otherwise, equivalent to \tcode{\exposid{unex} = std::move(rhs.\exposid{unex})}.
23512351
\end{itemize}
23522352

23532353
\pnum
@@ -2396,7 +2396,7 @@
23962396
\end{codeblock}
23972397
\item
23982398
Otherwise, equivalent to:
2399-
\tcode{\exposid{unex} = std::forward<GF>(e.error());}
2399+
\tcode{\exposid{unex} = unexpected<E>(std::forward<GF>(e.error()));}
24002400
\end{itemize}
24012401

24022402
\pnum
@@ -2546,7 +2546,7 @@
25462546

25472547
\pnum
25482548
\returns
2549-
\exposid{unex}.
2549+
\tcode{\exposid{unex}.error()}.
25502550
\end{itemdescr}
25512551

25522552
\indexlibrarymember{error}{expected<void>}%
@@ -2562,7 +2562,7 @@
25622562

25632563
\pnum
25642564
\returns
2565-
\tcode{std::move(\exposid{unex})}.
2565+
\tcode{std::move(\exposid{unex}).error()}.
25662566
\end{itemdescr}
25672567

25682568
\indexlibrarymember{error_or}{expected<void>}%

0 commit comments

Comments
 (0)