faq.html 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  2. <html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  3. <title>Frequently asked questions - Boost.Outcome documentation</title>
  4. <link rel="stylesheet" href="./css/boost.css" type="text/css">
  5. <meta name="generator" content="Hugo 0.52 with Boostdoc theme">
  6. <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
  7. <link rel="icon" href="./images/favicon.ico" type="image/ico"/>
  8. <body><div class="spirit-nav">
  9. <a accesskey="p" href="./reference/functions/try_throw_std_exception_from_error.html"><img src="./images/prev.png" alt="Prev"></a>
  10. <a accesskey="u" href="./index.html"><img src="./images/up.png" alt="Up"></a>
  11. <a accesskey="h" href="./index.html"><img src="./images/home.png" alt="Home"></a><a accesskey="n" href="./videos.html"><img src="./images/next.png" alt="Next"></a></div><div id="content">
  12. <div class="titlepage"><div><div><h1 style="clear: both">Frequently asked questions</h1></div></div></div>
  13. <div class="toc"><dl class="toc">
  14. <dt>
  15. <dd><dl>
  16. <dt><a href="#is-outcome-safe-to-use-in-extern-apis">Is Outcome safe to use in extern APIs?</a></dt>
  17. <dt><a href="#does-outcome-implement-over-alignment">Does Outcome implement over-alignment?</a></dt>
  18. <dt><a href="#does-outcome-implement-the-no-fail-strong-or-basic-exception-guarantee">Does Outcome implement the no-fail, strong or basic exception guarantee?</a></dt>
  19. <dt><a href="#does-outcome-have-a-stable-abi-and-api">Does Outcome have a stable ABI and API?</a></dt>
  20. <dt><a href="#can-i-use-result-t-ec-across-dll-shared-object-boundaries">Can I use <code>result&lt;T, EC&gt;</code> across DLL/shared object boundaries?</a></dt>
  21. <dt><a href="#why-two-types-result-and-outcome-rather-than-just-one">Why two types <code>result&lt;&gt;</code> and <code>outcome&lt;&gt;</code>, rather than just one?</a></dt>
  22. <dt><a href="#how-badly-will-including-outcome-in-my-public-interface-affect-compile-times">How badly will including Outcome in my public interface affect compile times?</a></dt>
  23. <dt><a href="#is-outcome-suitable-for-fixed-latency-predictable-execution-coding-such-as-for-high-frequency-trading-or-audio">Is Outcome suitable for fixed latency/predictable execution coding such as for high frequency trading or audio?</a></dt>
  24. <dt><a href="#what-kind-of-runtime-performance-impact-will-using-outcome-in-my-code-introduce">What kind of runtime performance impact will using Outcome in my code introduce?</a>
  25. <dd><dl>
  26. <dt><a href="#high-end-cpu-intel-skylake-x64">High end CPU: Intel Skylake x64</a></dt>
  27. <dt><a href="#mid-tier-cpu-arm-cortex-a72">Mid tier CPU: ARM Cortex A72</a></dt>
  28. <dt><a href="#low-end-cpus-intel-silvermont-x64-and-arm-cortex-a53">Low end CPUs: Intel Silvermont x64 and ARM Cortex A53</a></dt>
  29. </dl></dd></dt>
  30. <dt><a href="#why-is-implicit-default-construction-disabled">Why is implicit default construction disabled?</a></dt>
  31. <dt><a href="#how-far-away-from-the-proposed-std-expected-t-e-is-outcome-s-checked-t-e">How far away from the proposed <code>std::expected&lt;T, E&gt;</code> is Outcome&rsquo;s <code>checked&lt;T, E&gt;</code>?</a></dt>
  32. <dt><a href="#why-doesn-t-outcome-duplicate-std-expected-t-e-s-design">Why doesn&rsquo;t Outcome duplicate <code>std::expected&lt;T, E&gt;</code>&rsquo;s design?</a></dt>
  33. <dt><a href="#is-outcome-riddled-with-undefined-behaviour-for-const-const-containing-and-reference-containing-types">Is Outcome riddled with undefined behaviour for const, const-containing and reference-containing types?</a>
  34. <dd><dl>
  35. <dt><a href="#more-detail">More detail</a></dt>
  36. </dl></dd></dt>
  37. </dl></dd></dt>
  38. </dl>
  39. </div>
  40. <h2 id="is-outcome-safe-to-use-in-extern-apis">Is Outcome safe to use in extern APIs?</h2>
  41. <p>Outcome is specifically designed for use in the public interfaces of multi-million
  42. line codebases. <code>result</code>&rsquo;s layout is hard coded to:</p>
  43. <div class="highlight"><pre class="chroma"><code class="language-c" data-lang="c"><span class="k">struct</span>
  44. <span class="p">{</span>
  45. <span class="n">T</span> <span class="n">value</span><span class="p">;</span>
  46. <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">;</span>
  47. <span class="n">EC</span> <span class="n">error</span><span class="p">;</span>
  48. <span class="p">};</span></code></pre></div>
  49. <p>This is C-compatible if <code>T</code> and <code>EC</code> are C-compatible.
  50. <a href="https://en.cppreference.com/w/cpp/error/error_code" class="api-reference" target="_blank"><i class="fa fa-book" aria-hidden="true"></i> <code>std::error_code</code></a>
  51. is <em>probably</em> C-compatible, but its layout is not standardised (though there is a
  52. normative note in the standard about its layout). Hence Outcome cannot provide a
  53. C macro API for standard Outcome, but we can for <a href="./experimental/c-api.html">Experimental Outcome</a>.</p>
  54. <h2 id="does-outcome-implement-over-alignment">Does Outcome implement over-alignment?</h2>
  55. <p>Variant-based alternatives to Outcome such as
  56. <a href="https://wg21.link/P0323" class="api-reference" target="_blank"><i class="fa fa-book" aria-hidden="true"></i> P0323 <code>std::expected&lt;T, E&gt;</code></a>
  57. would use <code>std::aligned_union</code> to ensure appropriate over-alignment for the storage of
  58. either a <code>T</code> or an <code>E</code>. This discovers the over-alignment for a type using
  59. <code>std::alignment_of</code>, which is defaulted to <code>alignof()</code>.</p>
  60. <p>Outcome uses <code>struct</code>-based storage, as described above. Any over-alignment of
  61. <code>result</code> or <code>outcome</code> will follow the ordinary alignment and padding rules for
  62. <code>struct</code> on your compiler. Traits such as <code>std::alignment_of</code>, or other standard
  63. library facilities, are not used.</p>
  64. <h2 id="does-outcome-implement-the-no-fail-strong-or-basic-exception-guarantee">Does Outcome implement the no-fail, strong or basic exception guarantee?</h2>
  65. <p>(<a href="https://en.cppreference.com/w/cpp/language/exceptions#Exception_safety">You can read about the meaning of these guarantees at cppreference.com</a>)</p>
  66. <p>If for the following operations:</p>
  67. <ul>
  68. <li>Construction</li>
  69. <li>Assignment</li>
  70. <li>Swap</li>
  71. </ul>
  72. <p>&hellip; the corresponding operation in <strong>all</strong> of <code>value_type</code>, <code>error_type</code> (and
  73. <code>exception_type</code> for <code>outcome</code>) is <code>noexcept(true)</code>, then <code>result</code> and
  74. <code>outcome</code>&rsquo;s operation is <code>noexcept(true)</code>. This propagates the no-fail exception
  75. guarantee of the underlying types. Otherwise the basic guarantee applies for all
  76. but Swap, under the same rules as for the <code>struct</code> layout type given above e.g.
  77. value would be constructed first, then the flags, then the error. If the error
  78. throws, value and status bits would be as if the failure had not occurred, same
  79. as for aborting the construction of any <code>struct</code> type.</p>
  80. <p>It is recognised that these weak guarantees may be unsuitable for some people,
  81. so Outcome implements <code>swap()</code> with much stronger guarantees, as one can locally refine,
  82. without too much work, one&rsquo;s own custom classes from <code>result</code> and <code>outcome</code> implementing
  83. stronger guarantees for construction and assignment using <code>swap()</code> as the primitive
  84. building block.</p>
  85. <p>The core ADL discovered implementation of strong guarantee swap is <a href="./reference/functions/strong_swap.html" class="api-reference"><code>strong_swap(bool &amp;all_good, T &amp;a, T &amp;b)</code></a>
  86. .
  87. This can be overloaded by third party code with custom strong guarantee swap
  88. implementations, same as for <code>std::swap()</code>. Because strong guarantee swap may fail
  89. when trying to restore input state during handling of failure to swap, the
  90. <code>all_good</code> boolean becomes false if restoration fails, at which point both
  91. results/outcomes get marked as tainted via <a href="./reference/types/basic_result/has_lost_consistency.html" class="api-reference"><code>has_lost_consistency()</code></a>
  92. .</p>
  93. <p>It is <strong>up to you</strong> to check this flag to see if known good state has been lost,
  94. as Outcome never does so on your behalf. The simple solution to avoiding having
  95. to deal with this situation is to always choose your value, error and exception
  96. types to have non-throwing move constructors and move assignments. This causes
  97. the strong swap implementation to no longer be used, as it is no longer required,
  98. and standard swap is used instead.</p>
  99. <h2 id="does-outcome-have-a-stable-abi-and-api">Does Outcome have a stable ABI and API?</h2>
  100. <p>Right now, no. Though the data layout shown above is not expected to change.</p>
  101. <p>Outcome&rsquo;s ABI and API will be formally fixed as <strong>the</strong> v2 interface approximately
  102. one year after its first Boost release. Thereafter the
  103. <a href="https://lvc.github.io/abi-compliance-checker/">ABI compliance checker</a>
  104. will be run per-commit to ensure Outcome&rsquo;s ABI and API remains stable.</p>
  105. <p>Note that the stable ABI and API guarantee will only apply to standalone
  106. Outcome, not to Boost.Outcome. Boost.Outcome has dependencies on other
  107. parts of Boost which are not stable across releases.</p>
  108. <p>Note also that the types you configure a <code>result</code> or <code>outcome</code> with also need
  109. to be ABI stable if <code>result</code> or <code>outcome</code> is to be ABI stable.</p>
  110. <h2 id="can-i-use-result-t-ec-across-dll-shared-object-boundaries">Can I use <code>result&lt;T, EC&gt;</code> across DLL/shared object boundaries?</h2>
  111. <p>A known problem with using DLLs (and to smaller extent shared libraries) is that global
  112. objects may get duplicated: one instance in the executable and one in the DLL. This
  113. behaviour is not incorrect according to the C++ Standard, as the Standard does not
  114. recognize the existence of DLLs or shared libraries. Therefore, program designs that
  115. depend on globals having unique addresses may become compromised when used in a program
  116. using DLLs.</p>
  117. <p>Nothing in Outcome depends on the addresses of globals, plus the guaranteed fixed data
  118. layout (see answer above) means that different versions of Outcome can be used in
  119. different DLLs, and it probably will work okay (it is still not advised that you do that
  120. as that is an ODR violation).
  121. However, one of the most likely candidate for <code>EC</code> &ndash; <code>std::error_code</code> &ndash; does depend
  122. on the addresses of globals for correct functioning.</p>
  123. <p>The standard library is required to implement globally unique addresses for the standard library
  124. provided
  125. <a href="https://en.cppreference.com/w/cpp/error/error_category" class="api-reference" target="_blank"><i class="fa fa-book" aria-hidden="true"></i> <code>std::error_category</code></a>
  126. implementations e.g. <code>std::system_category()</code>.
  127. User defined error code categories may <strong>not</strong> have unique global addresses, and thus
  128. introduce misoperation.</p>
  129. <p><code>boost::system::error_code</code>, since version 1.69 does offer an <em>opt-in</em> guarantee
  130. that it does not depend on the addresses of globals <strong>if</strong> the user defined error code
  131. category <em>opts-in</em> to the 64-bit comparison mechanism. This can be seen in the specification of
  132. <code>error_category::operator==</code> in
  133. <a href="https://www.boost.org/doc/libs/1_69_0/libs/system/doc/html/system.html#ref_synopsis">Boost.System synopsis</a>.</p>
  134. <p>Alternatively, the <code>status_code</code> in <a href="(/experimental/differences.html)">Experimental Outcome</a>,
  135. due to its more modern design, does not suffer from any problems from being used in shared
  136. libraries in any configuration.</p>
  137. <h2 id="why-two-types-result-and-outcome-rather-than-just-one">Why two types <code>result&lt;&gt;</code> and <code>outcome&lt;&gt;</code>, rather than just one?</h2>
  138. <p><code>result</code> is the simple, success OR failure type.</p>
  139. <p><code>outcome</code> extends <code>result</code> with a third state to transport, conventionally (but not necessarily) some sort of &ldquo;abort&rdquo; or &ldquo;exceptional&rdquo; state which a function can return to indicate that not only did the operation fail, but it did so <em>catastrophically</em> i.e. please abort any attempt to retry the operation.</p>
  140. <p>A perfect alternative to using <code>outcome</code> is to throw a C++ exception for the abort code path, and indeed most programs ought to do exactly that instead of using <code>outcome</code>. However there are a number of use cases where choosing <code>outcome</code> shines:</p>
  141. <ol>
  142. <li>Where C++ exceptions or RTTI is not available, but the ability to fail catastrophically without terminating the program is important.</li>
  143. <li>Where deterministic behaviour is required even in the catastrophic failure situation.</li>
  144. <li>In unit test suites of code using Outcome it is extremely convenient to accumulate test failures into an <code>outcome</code> for later reporting. A similar convenience applies to RPC situations, where C++ exception throws need to be accumulated for reporting back to the initiating endpoint.</li>
  145. <li>Where a function is &ldquo;dual use deterministic&rdquo; i.e. it can be used deterministically, in which case one switches control flow based on <code>.error()</code>, or it can be used non-deterministically by throwing an exception perhaps carrying a custom payload.</li>
  146. </ol>
  147. <h2 id="how-badly-will-including-outcome-in-my-public-interface-affect-compile-times">How badly will including Outcome in my public interface affect compile times?</h2>
  148. <p>The quick answer is that it depends on how much convenience you want.</p>
  149. <p>The convenience header <code>&lt;result.hpp&gt;</code> is dependent on <code>&lt;system_error&gt;</code> or Boost.System, which unfortunately includes <code>&lt;string&gt;</code> and thus
  150. drags in quite a lot of other slow-to-parse stuff. If your public interface already includes <code>&lt;string&gt;</code>,
  151. then the impact of additionally including Outcome will be low. If you do not include <code>&lt;string&gt;</code>,
  152. unfortunately impact may be relatively quite high, depending on the total impact of your
  153. public interface files.</p>
  154. <p>If you&rsquo;ve been extremely careful to avoid ever including the most of the STL headers
  155. into your interfaces in order to maximise build performance, then <code>&lt;basic_result.hpp&gt;</code>
  156. can have as few dependencies as:</p>
  157. <ol>
  158. <li><code>&lt;cstdint&gt;</code></li>
  159. <li><code>&lt;initializer_list&gt;</code></li>
  160. <li><code>&lt;iosfwd&gt;</code></li>
  161. <li><code>&lt;new&gt;</code></li>
  162. <li><code>&lt;type_traits&gt;</code></li>
  163. <li><code>&lt;cstdio&gt;</code></li>
  164. <li><code>&lt;cstdlib&gt;</code></li>
  165. <li><code>&lt;cassert&gt;</code></li>
  166. </ol>
  167. <p>These, apart from <code>&lt;iosfwd&gt;</code>, tend to be very low build time impact in most standard
  168. library implementations. If you include only <code>&lt;basic_result.hpp&gt;</code>, and manually configure
  169. <code>basic_result&lt;&gt;</code> by hand, compile time impact will be minimised.</p>
  170. <p>(See reference documentation for <a href="./reference/types/basic_result.html" class="api-reference"><code>basic_result&lt;T, E, NoValuePolicy&gt;</code></a>
  171. for more detail.</p>
  172. <h2 id="is-outcome-suitable-for-fixed-latency-predictable-execution-coding-such-as-for-high-frequency-trading-or-audio">Is Outcome suitable for fixed latency/predictable execution coding such as for high frequency trading or audio?</h2>
  173. <p>Great care has been taken to ensure that Outcome never unexpectedly executes anything
  174. with unbounded execution times such as <code>malloc()</code>, <code>dynamic_cast&lt;&gt;()</code> or <code>throw</code>.
  175. Outcome works perfectly with C++ exceptions and RTTI globally disabled.</p>
  176. <p>Outcome&rsquo;s entire design premise is that its users are happy to exchange a small, predictable constant overhead
  177. during successful code paths, in exchange for predictable failure code paths.</p>
  178. <p>In contrast, table-based exception handling gives zero run time overhead for the
  179. successful code path, and completely unpredictable (and very expensive) overhead
  180. for failure code paths.</p>
  181. <p>For code where predictability of execution, no matter the code path, is paramount,
  182. writing all your code to use Outcome is not a bad place to start. Obviously enough,
  183. do choose a non-throwing policy when configuring <code>outcome</code> or <code>result</code> such as
  184. <a href="./reference/policies/all_narrow.html" class="api-reference"><code>all_narrow</code></a>
  185. to guarantee that exceptions can never be thrown by Outcome
  186. (or use the convenience typedef for <code>result</code>, <a href="./reference/aliases/unchecked.html" class="api-reference"><code>unchecked&lt;T, E = varies&gt;</code></a>
  187. which uses <code>policy::all_narrow</code>).</p>
  188. <h2 id="what-kind-of-runtime-performance-impact-will-using-outcome-in-my-code-introduce">What kind of runtime performance impact will using Outcome in my code introduce?</h2>
  189. <p>It is very hard to say anything definitive about performance impacts in codebases one
  190. has never seen. Each codebase is unique. However to come up with some form of measure,
  191. we timed traversing ten stack frames via each of the main mechanisms, including the
  192. &ldquo;do nothing&rdquo; (null) case.</p>
  193. <p>A stack frame is defined to be something called by the compiler whilst
  194. unwinding the stack between the point of return in the ultimate callee and the base
  195. caller, so for example ten stack allocated objects might be destructed, or ten levels
  196. of stack depth might be unwound. This is not a particularly realistic test, but it
  197. should at least give one an idea of the performance impact of returning Outcome&rsquo;s
  198. <code>result</code> or <code>outcome</code> over say returning a plain integer, or throwing an exception.</p>
  199. <h3 id="high-end-cpu-intel-skylake-x64">High end CPU: Intel Skylake x64</h3>
  200. <p>This is a high end CPU with very significant ability to cache, predict, parallelise
  201. and execute out-of-order such that tight, repeated loops perform very well. It has
  202. a large μop cache able to wholly contain the test loop, meaning that these results
  203. are a <strong>best case</strong> performance.</p>
  204. <figure>
  205. <img src="./faq/results_skylake_log.png"/> <figcaption>
  206. <h4>Log graph comparing GCC 7.4, clang 8.0 and Visual Studio 2017.9 on x64, for exceptions-globally-disabled, ordinary and link-time-optimised build configurations.</h4>
  207. </figcaption>
  208. </figure>
  209. <p>As you can see, throwing and catching an exception is
  210. expensive on table-based exception handling implementations such as these, anywhere
  211. between 26,000 and 43,000 CPU cycles. And this is the <em>hot path</em> situation, this
  212. benchmark is a loop around hot cached code. If the tables are paged out onto storage,
  213. you are talking about <strong>millions</strong> of CPU cycles.</p>
  214. <p>Simple integer returns (i.e. do nothing null case)
  215. are always going to be the fastest as they do the least work, and that costs 80 to 90
  216. CPU cycles on this Intel Skylake CPU.</p>
  217. <p>Note that returning a <code>result&lt;int, std::error_code&gt;</code> with a &ldquo;success (error code)&rdquo;
  218. is no more than 5% added runtime overhead over returning a naked int on GCC and clang. On MSVC
  219. it costs an extra 20% or so, mainly due to poor code optimisation in the VS2017.9 compiler. Note that &ldquo;success
  220. (experimental status code)&rdquo; optimises much better, and has almost no overhead over a
  221. naked int.</p>
  222. <p>Returning a <code>result&lt;int, std::error_code&gt;</code> with a &ldquo;failure (error code)&rdquo;
  223. is less than 5% runtime overhead over returning a success on GCC, clang and MSVC.</p>
  224. <p>You might wonder what happens if type <code>E</code> has a non-trivial destructor, thus making the
  225. <code>result&lt;T, E&gt;</code> have a non-trivial destructor? We tested <code>E = std::exception_ptr</code> and
  226. found less than a 5% overhead to <code>E = std::error_code</code> for returning success. Returning a failure
  227. was obviously much slower at anywhere between 300 and 1,100 CPU cycles, due to the
  228. dynamic memory allocation and free of the exception ptr, plus at least two atomic operations per stack frame, but that is
  229. still two orders of magnitude better than throwing and catching an exception.</p>
  230. <p>We conclude that if failure is anything but extremely rare in your C++ codebase,
  231. using Outcome instead of throwing and catching exceptions ought to be quicker overall:</p>
  232. <ul>
  233. <li>Experimental Outcome is statistically indistinguishable from the null case on this
  234. high end CPU, for both returning success and failure, on all compilers.</li>
  235. <li>Standard Outcome is less than 5%
  236. worse than the null case for returning successes on GCC and clang, and less than 10% worse than
  237. the null case for returning failures on GCC and clang.</li>
  238. <li>Standard Outcome optimises
  239. poorly on VS2017.9, indeed markedly worse than on previous point releases, so let&rsquo;s
  240. hope that Microsoft fix that soon. It currently has a less than 20% overhead on the null case.</li>
  241. </ul>
  242. <h3 id="mid-tier-cpu-arm-cortex-a72">Mid tier CPU: ARM Cortex A72</h3>
  243. <p>This is a four year old mid tier CPU used in many high end mobile phones and tablets
  244. of its day, with good ability to cache, predict, parallelise
  245. and execute out-of-order such that tight, repeated loops perform very well. It has
  246. a μop cache able to wholly contain the test loop, meaning that these results
  247. are a <strong>best case</strong> performance.</p>
  248. <figure>
  249. <img src="./faq/results_arm_a72_log.png"/> <figcaption>
  250. <h4>Log graph comparing GCC 7.3 and clang 7.3 on ARM64, for exceptions-globally-disabled, ordinary and link-time-optimised build configurations.</h4>
  251. </figcaption>
  252. </figure>
  253. <p>This ARM chip is a very consistent performer &ndash; null case, success, or failure, all take
  254. almost exactly the same CPU cycles. Choosing Outcome, in any configuration, makes no
  255. difference to not using Outcome at all. Throwing and catching a C++ exception costs
  256. about 90,000 CPU cycles, whereas the null case/Outcome costs about 130 - 140 CPU cycles.</p>
  257. <p>There is very little to say about this CPU, other than Outcome is zero overhead on it. The same
  258. applied to the ARM Cortex A15 incidentally, which I test cased extensively when
  259. deciding on the Outcome v2 design back after the first peer review. The v2 design
  260. was chosen partially because of such consistent performance on ARM.</p>
  261. <h3 id="low-end-cpus-intel-silvermont-x64-and-arm-cortex-a53">Low end CPUs: Intel Silvermont x64 and ARM Cortex A53</h3>
  262. <p>These are low end CPUs with a mostly or wholly in-order execution core. They have a small
  263. or no μop cache, meaning that the CPU must always decode the instruction stream.
  264. These results represent an execution environment more typical of CPUs two decades
  265. ago, back when table-based EH created a big performance win if you never threw
  266. an exception.</p>
  267. <p><figure>
  268. <img src="./faq/results_silvermont_log.png"/> <figcaption>
  269. <h4>Log graph comparing GCC 7.3 and clang 7.3 on x64, for exceptions-globally-disabled, ordinary and link-time-optimised build configurations.</h4>
  270. </figcaption>
  271. </figure>
  272. <figure>
  273. <img src="./faq/results_arm_a53_log.png"/> <figcaption>
  274. <h4>Log graph comparing GCC 7.3 and clang 7.3 on ARM64, for exceptions-globally-disabled, ordinary and link-time-optimised build configurations.</h4>
  275. </figcaption>
  276. </figure></p>
  277. <p>The first thing to mention is that clang generates very high performance code for
  278. in-order cores, far better than GCC. It is said that this is due to a very large investment by
  279. Apple in clang/LLVM for their devices sustained over many years. In any case, if you&rsquo;re
  280. targeting in-order CPUs, don&rsquo;t use GCC if you can use clang instead!</p>
  281. <p>For the null case, Silvermont and Cortex A53 are quite similar in terms of CPU clock cycles. Ditto
  282. for throwing and catching a C++ exception (approx 150,000 CPU cycles). However the Cortex
  283. A53 does far better with Outcome than Silvermont, a 15% versus 100% overhead for Standard
  284. Outcome, and a 4% versus 20% overhead for Experimental Outcome.</p>
  285. <p>Much of this large difference is in fact due to calling convention differences. x64 permits up to 8 bytes
  286. to be returned from functions by CPU register. <code>result&lt;int&gt;</code> consumes 24 bytes, so on x64
  287. the compiler writes the return value to the stack. However ARM64 permits up to 64 bytes
  288. to be returned in registers, so <code>result&lt;int&gt;</code> is returned via CPU registers on ARM64.</p>
  289. <p>On higher end CPUs, memory is read and written in cache lines (32 or 64 bytes), and
  290. reads and writes are coalesced and batched together by the out-of-order execution core. On these
  291. low end CPUs, memory is read and written sequentially per assembler instruction,
  292. so only one load or one store to L1
  293. cache can occur at a time. This makes writing the stack particularly slow on in-order
  294. CPUs. Memory operations which &ldquo;disappear&rdquo; on higher end CPUs take considerable time
  295. on low end CPUs. This particularly punishes Silvermont in a way which does not punish
  296. the Cortex A53, because of having to write multiple values to the stack to create the
  297. 24 byte object to be returned.</p>
  298. <p>The conclusion to take away from this is that if you are targeting a low end CPU,
  299. table-based EH still delivers significant performance improvements for the success
  300. code path. Unless determinism in failure is critically important, you should not
  301. use Outcome on in-order execution CPUs.</p>
  302. <h2 id="why-is-implicit-default-construction-disabled">Why is implicit default construction disabled?</h2>
  303. <p>This was one of the more interesting points of discussion during the peer review of
  304. Outcome v1. v1 had a formal empty state. This came with many advantages, but it
  305. was not felt to be STL idiomatic as <code>std::optional&lt;result&lt;T&gt;&gt;</code> is what was meant, so
  306. v2 has eliminated any legal possibility of being empty.</p>
  307. <p>The <code>expected&lt;T, E&gt;</code> proposal of that time (May 2017) did permit default construction
  308. if its <code>T</code> type allowed default construction. This was specifically done to make
  309. <code>expected&lt;T, E&gt;</code> more useful in STL containers as one can say resize a vector without
  310. having to supply an <code>expected&lt;T, E&gt;</code> instance to fill the new items with. However
  311. there was some unease with that design choice, because it may cause programmers to
  312. use some type <code>T</code> whose default constructed state is overloaded with additional meaning,
  313. typically &ldquo;to be filled&rdquo; i.e. a de facto empty state via choosing a magic value.</p>
  314. <p>For the v2 redesign, the various arguments during the v1 review were considered.
  315. Unlike <code>expected&lt;T, E&gt;</code> which is intended to be a general purpose Either monad
  316. vocabulary type, Outcome&rsquo;s types are meant primarily for returning success or failure
  317. from functions. The API should therefore encourage the programmer to not overload
  318. the successful type with additional meaning of &ldquo;to be filled&rdquo; e.g. <code>result&lt;std::optional&lt;T&gt;&gt;</code>.
  319. The decision was therefore taken to disable <em>implicit</em> default construction, but
  320. still permit <em>explicit</em> default construction by making the programmer spell out their
  321. intention with extra typing.</p>
  322. <p>To therefore explicitly default construct a <code>result&lt;T&gt;</code> or <code>outcome&lt;T&gt;</code>, use one
  323. of these forms as is the most appropriate for the use case:</p>
  324. <ol>
  325. <li>Construct with just <code>in_place_type&lt;T&gt;</code> e.g. <code>result&lt;T&gt;(in_place_type&lt;T&gt;)</code>.</li>
  326. <li>Construct via <code>success()</code> e.g. <code>outcome&lt;T&gt;(success())</code>.</li>
  327. <li>Construct from a <code>void</code> form e.g. <code>result&lt;T&gt;(result&lt;void&gt;(in_place_type&lt;void&gt;))</code>.</li>
  328. </ol>
  329. <h2 id="how-far-away-from-the-proposed-std-expected-t-e-is-outcome-s-checked-t-e">How far away from the proposed <code>std::expected&lt;T, E&gt;</code> is Outcome&rsquo;s <code>checked&lt;T, E&gt;</code>?</h2>
  330. <p>Not far, in fact after the first Boost.Outcome peer review in May 2017, Expected moved
  331. much closer to Outcome, and Outcome deliberately provides <a href="./reference/aliases/checked.html" class="api-reference"><code>checked&lt;T, E = varies&gt;</code></a>
  332. as a semantic equivalent.</p>
  333. <p>Here are the remaining differences which represent the
  334. divergence of consensus opinion between the Boost peer review and WG21 on the proper
  335. design for this object:</p>
  336. <ol>
  337. <li><code>checked&lt;T, E&gt;</code> has no default constructor. Expected has a default constructor if
  338. <code>T</code> has a default constructor.</li>
  339. <li><code>checked&lt;T, E&gt;</code> uses the same constructor design as <code>std::variant&lt;...&gt;</code>. Expected
  340. uses the constructor design of <code>std::optional&lt;T&gt;</code>.</li>
  341. <li><code>checked&lt;T, E&gt;</code> cannot be modified after construction except by assignment.
  342. Expected provides an <code>.emplace()</code> modifier.</li>
  343. <li><code>checked&lt;T, E&gt;</code> permits implicit construction from both <code>T</code> and <code>E</code> when
  344. unambiguous. Expected permits implicit construction from <code>T</code> alone.</li>
  345. <li><code>checked&lt;T, E&gt;</code> does not permit <code>T</code> and <code>E</code> to be the same, and becomes annoying
  346. to use if they are constructible into one another (implicit construction self-disables).
  347. Expected permits <code>T</code> and <code>E</code> to be the same.</li>
  348. <li><code>checked&lt;T, E&gt;</code> throws <code>bad_result_access_with&lt;E&gt;</code> instead of Expected&rsquo;s
  349. <code>bad_expected_access&lt;E&gt;</code>.</li>
  350. <li><code>checked&lt;T, E&gt;</code> models <code>std::variant&lt;...&gt;</code>. Expected models <code>std::optional&lt;T&gt;</code>. Thus:
  351. <ul>
  352. <li><code>checked&lt;T, E&gt;</code> does not provide <code>operator*()</code> nor <code>operator-&gt;</code></li>
  353. <li><code>checked&lt;T, E&gt;</code> <code>.error()</code> is wide (i.e. throws on no-value) like <code>.value()</code>.
  354. Expected&rsquo;s <code>.error()</code> is narrow (UB on no-error). [<code>checked&lt;T, E&gt;</code> provides
  355. <code>.assume_value()</code> and <code>.assume_error()</code> for narrow (UB causing) observers].</li>
  356. </ul></li>
  357. <li><code>checked&lt;T, E&gt;</code> uses <code>success&lt;T&gt;</code> and <code>failure&lt;E&gt;</code> type sugars for disambiguation.
  358. Expected uses <code>unexpected&lt;E&gt;</code> only.</li>
  359. <li><code>checked&lt;T, E&gt;</code> requires <code>E</code> to be default constructible.</li>
  360. <li><code>checked&lt;T, E&gt;</code> defaults <code>E</code> to <code>std::error_code</code> or <code>boost::system::error_code</code>.
  361. Expected does not default <code>E</code>.</li>
  362. </ol>
  363. <p>In fact, the two are sufficiently close in design that a highly conforming <code>expected&lt;T, E&gt;</code>
  364. can be implemented by wrapping up <code>checked&lt;T, E&gt;</code> with the differing functionality:</p>
  365. <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="cm">/* Here is a fairly conforming implementation of P0323R3 `expected&lt;T, E&gt;` using `checked&lt;T, E&gt;`.
  366. </span><span class="cm">It passes the reference test suite for P0323R3 at
  367. </span><span class="cm">https://github.com/viboes/std-make/blob/master/test/expected/expected_pass.cpp with modifications
  368. </span><span class="cm">only to move the test much closer to the P0323R3 Expected, as the reference test suite is for a
  369. </span><span class="cm">much older proposed Expected.
  370. </span><span class="cm">
  371. </span><span class="cm">Known differences from P0323R3 in this implementation:
  372. </span><span class="cm">- `T` and `E` cannot be the same type.
  373. </span><span class="cm">- `E` must be default constructible.
  374. </span><span class="cm">- No variant storage is implemented (note the Expected proposal does not actually require this).
  375. </span><span class="cm">*/</span>
  376. <span class="k">namespace</span> <span class="n">detail</span>
  377. <span class="p">{</span>
  378. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">using</span> <span class="n">expected_result</span> <span class="o">=</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">checked</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span><span class="p">;</span>
  379. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="nl">enable_default_constructor</span> <span class="p">:</span> <span class="k">public</span> <span class="n">expected_result</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span>
  380. <span class="p">{</span>
  381. <span class="k">using</span> <span class="n">base</span> <span class="o">=</span> <span class="n">expected_result</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span><span class="p">;</span>
  382. <span class="k">using</span> <span class="n">base</span><span class="o">::</span><span class="n">base</span><span class="p">;</span>
  383. <span class="k">constexpr</span> <span class="nf">enable_default_constructor</span><span class="p">()</span>
  384. <span class="o">:</span> <span class="n">base</span><span class="p">{</span><span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">in_place_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">}</span>
  385. <span class="p">{</span>
  386. <span class="p">}</span>
  387. <span class="p">};</span>
  388. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">using</span> <span class="n">select_expected_base</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">conditional_t</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">is_default_constructible</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">,</span> <span class="n">enable_default_constructor</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">expected_result</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;&gt;</span><span class="p">;</span>
  389. <span class="p">}</span>
  390. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">class</span><span class="err"> </span><span class="nc">expected</span> <span class="o">:</span> <span class="k">public</span> <span class="n">detail</span><span class="o">::</span><span class="n">select_expected_base</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span>
  391. <span class="p">{</span>
  392. <span class="k">static_assert</span><span class="p">(</span><span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">,</span> <span class="s">&#34;T and E cannot be the same in this expected implementation&#34;</span><span class="p">);</span>
  393. <span class="k">using</span> <span class="n">base</span> <span class="o">=</span> <span class="n">detail</span><span class="o">::</span><span class="n">select_expected_base</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span><span class="p">;</span>
  394. <span class="k">public</span><span class="o">:</span>
  395. <span class="c1">// Inherit base&#39;s constructors
  396. </span><span class="c1"></span> <span class="k">using</span> <span class="n">base</span><span class="o">::</span><span class="n">base</span><span class="p">;</span>
  397. <span class="n">expected</span><span class="p">()</span> <span class="o">=</span> <span class="k">default</span><span class="p">;</span>
  398. <span class="c1">// Expected takes in_place not in_place_type
  399. </span><span class="c1"></span> <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err">... </span><span class="nc">Args</span><span class="o">&gt;</span>
  400. <span class="k">constexpr</span> <span class="k">explicit</span> <span class="n">expected</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">in_place_t</span> <span class="cm">/*unused*/</span><span class="p">,</span> <span class="n">Args</span> <span class="o">&amp;&amp;</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span>
  401. <span class="o">:</span> <span class="n">base</span><span class="p">{</span><span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">in_place_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)...}</span>
  402. <span class="p">{</span>
  403. <span class="p">}</span>
  404. <span class="c1">// Expected always accepts a T even if ambiguous
  405. </span><span class="c1"></span> <span class="n">BOOST_OUTCOME_TEMPLATE</span><span class="p">(</span><span class="k">class</span><span class="err"> </span><span class="nc">U</span><span class="p">)</span>
  406. <span class="n">BOOST_OUTCOME_TREQUIRES</span><span class="p">(</span><span class="n">BOOST_OUTCOME_TPRED</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_constructible</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">))</span>
  407. <span class="k">constexpr</span> <span class="n">expected</span><span class="p">(</span><span class="n">U</span> <span class="o">&amp;&amp;</span><span class="n">v</span><span class="p">)</span>
  408. <span class="o">:</span> <span class="n">base</span><span class="p">{</span><span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">in_place_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">U</span><span class="o">&gt;</span><span class="p">(</span><span class="n">v</span><span class="p">)}</span>
  409. <span class="p">{</span>
  410. <span class="p">}</span>
  411. <span class="c1">// Expected has an emplace() modifier
  412. </span><span class="c1"></span> <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err">... </span><span class="nc">Args</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">emplace</span><span class="p">(</span><span class="n">Args</span> <span class="o">&amp;&amp;</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span> <span class="o">*</span><span class="k">static_cast</span><span class="o">&lt;</span><span class="n">base</span> <span class="o">*&gt;</span><span class="p">(</span><span class="k">this</span><span class="p">)</span> <span class="o">=</span> <span class="n">base</span><span class="p">{</span><span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">in_place_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)...};</span> <span class="p">}</span>
  413. <span class="c1">// Expected has a narrow operator* and operator-&gt;
  414. </span><span class="c1"></span> <span class="k">constexpr</span> <span class="k">const</span> <span class="n">T</span> <span class="o">&amp;</span><span class="k">operator</span><span class="o">*</span><span class="p">()</span> <span class="k">const</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  415. <span class="k">constexpr</span> <span class="n">T</span> <span class="o">&amp;</span><span class="k">operator</span><span class="o">*</span><span class="p">()</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  416. <span class="k">constexpr</span> <span class="k">const</span> <span class="n">T</span> <span class="o">&amp;&amp;</span><span class="k">operator</span><span class="o">*</span><span class="p">()</span> <span class="k">const</span> <span class="o">&amp;&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  417. <span class="k">constexpr</span> <span class="n">T</span> <span class="o">&amp;&amp;</span><span class="k">operator</span><span class="o">*</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  418. <span class="k">constexpr</span> <span class="k">const</span> <span class="n">T</span> <span class="o">*</span><span class="k">operator</span><span class="o">-&gt;</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="o">&amp;</span><span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  419. <span class="k">constexpr</span> <span class="n">T</span> <span class="o">*</span><span class="k">operator</span><span class="o">-&gt;</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="o">&amp;</span><span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  420. <span class="c1">// Expected has a narrow error() observer
  421. </span><span class="c1"></span> <span class="k">constexpr</span> <span class="k">const</span> <span class="n">E</span> <span class="o">&amp;</span><span class="n">error</span><span class="p">()</span> <span class="k">const</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_error</span><span class="p">();</span> <span class="p">}</span>
  422. <span class="k">constexpr</span> <span class="n">E</span> <span class="o">&amp;</span><span class="n">error</span><span class="p">()</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_error</span><span class="p">();</span> <span class="p">}</span>
  423. <span class="k">constexpr</span> <span class="k">const</span> <span class="n">E</span> <span class="o">&amp;&amp;</span><span class="n">error</span><span class="p">()</span> <span class="k">const</span> <span class="o">&amp;&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_error</span><span class="p">();</span> <span class="p">}</span>
  424. <span class="k">constexpr</span> <span class="n">E</span> <span class="o">&amp;</span><span class="n">error</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="p">{</span> <span class="k">return</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_error</span><span class="p">();</span> <span class="p">}</span>
  425. <span class="p">};</span>
  426. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">class</span><span class="err"> </span><span class="nc">expected</span><span class="o">&lt;</span><span class="kt">void</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="o">:</span> <span class="k">public</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">result</span><span class="o">&lt;</span><span class="kt">void</span><span class="p">,</span> <span class="n">E</span><span class="p">,</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">policy</span><span class="o">::</span><span class="n">throw_bad_result_access</span><span class="o">&lt;</span><span class="n">E</span><span class="p">,</span> <span class="kt">void</span><span class="o">&gt;&gt;</span>
  427. <span class="p">{</span>
  428. <span class="k">using</span> <span class="n">base</span> <span class="o">=</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">result</span><span class="o">&lt;</span><span class="kt">void</span><span class="p">,</span> <span class="n">E</span><span class="p">,</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">policy</span><span class="o">::</span><span class="n">throw_bad_result_access</span><span class="o">&lt;</span><span class="n">E</span><span class="p">,</span> <span class="kt">void</span><span class="o">&gt;&gt;</span><span class="p">;</span>
  429. <span class="k">public</span><span class="o">:</span>
  430. <span class="c1">// Inherit base constructors
  431. </span><span class="c1"></span> <span class="k">using</span> <span class="n">base</span><span class="o">::</span><span class="n">base</span><span class="p">;</span>
  432. <span class="c1">// Expected has a narrow operator* and operator-&gt;
  433. </span><span class="c1"></span> <span class="k">constexpr</span> <span class="kt">void</span> <span class="k">operator</span><span class="o">*</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  434. <span class="k">constexpr</span> <span class="kt">void</span> <span class="k">operator</span><span class="o">-&gt;</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="n">base</span><span class="o">::</span><span class="n">assume_value</span><span class="p">();</span> <span class="p">}</span>
  435. <span class="p">};</span>
  436. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">using</span> <span class="n">unexpected</span> <span class="o">=</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">failure_type</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span><span class="p">;</span>
  437. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="n">unexpected</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">make_unexpected</span><span class="p">(</span><span class="n">E</span> <span class="o">&amp;&amp;</span><span class="n">arg</span><span class="p">)</span>
  438. <span class="p">{</span>
  439. <span class="k">return</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">failure</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span><span class="p">(</span><span class="n">arg</span><span class="p">));</span>
  440. <span class="p">}</span>
  441. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="p">,</span> <span class="k">class</span><span class="err">... </span><span class="nc">Args</span><span class="o">&gt;</span> <span class="n">unexpected</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">make_unexpected</span><span class="p">(</span><span class="n">Args</span> <span class="o">&amp;&amp;</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span>
  442. <span class="p">{</span>
  443. <span class="k">return</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">failure</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)...);</span>
  444. <span class="p">}</span>
  445. <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">&gt;</span> <span class="k">using</span> <span class="n">bad_expected_access</span> <span class="o">=</span> <span class="n">BOOST_OUTCOME_V2_NAMESPACE</span><span class="o">::</span><span class="n">bad_result_access_with</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span><span class="p">;</span>
  446. </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/expected_implementation.cpp#L35" class="code-snippet-url" target="_blank">View this code on Github</a></div>
  447. <h2 id="why-doesn-t-outcome-duplicate-std-expected-t-e-s-design">Why doesn&rsquo;t Outcome duplicate <code>std::expected&lt;T, E&gt;</code>&rsquo;s design?</h2>
  448. <p>There are a number of reasons:</p>
  449. <ol>
  450. <li><p>Outcome is not aimed at the same audience as Expected. We target developers
  451. and users who would be happy to use Boost. Expected targets the standard library user.</p></li>
  452. <li><p>Outcome believes that the monadic use case isn&rsquo;t as important as Expected does.
  453. Specifically, we think that 99% of use of Expected in the real world will be to
  454. return failure from functions, and not as some sort of enhanced or &ldquo;rich&rdquo; Optional.
  455. Outcome therefore models a subset of Variant, whereas Expected models an extended Optional.</p></li>
  456. <li><p>Outcome believes that if you are thinking about using something like Outcome,
  457. then for you writing failure code will be in the same proportion as writing success code,
  458. and thus in Outcome writing for failure is exactly the same as writing for success.
  459. Expected assumes that success will be more common than failure, and makes you type
  460. more when writing for failure.</p></li>
  461. <li><p>Outcome goes to considerable effort to help the end user type fewer characters
  462. during use. This results in tighter, less verbose, more succinct code. The cost of this is a steeper
  463. learning curve and more complex mental model than when programming with Expected.</p></li>
  464. <li><p>Outcome has facilities to make easier interoperation between multiple third
  465. party libraries each using incommensurate Outcome (or Expected) configurations. Expected does
  466. not do any of this, but subsequent WG21 papers do propose various interoperation
  467. mechanisms, <a href="https://wg21.link/P0786">one of which</a> Outcome implements so code using Expected will seamlessly
  468. interoperate with code using Outcome.</p></li>
  469. </ol>
  470. <h2 id="is-outcome-riddled-with-undefined-behaviour-for-const-const-containing-and-reference-containing-types">Is Outcome riddled with undefined behaviour for const, const-containing and reference-containing types?</h2>
  471. <p>The short answer is not any more in C++ 20 and after, thanks to changes made to
  472. C++ 20 at the Belfast WG21 meeting in November 2019.</p>
  473. <p>The longer answer is that before C++ 20, use of placement
  474. new on types containing <code>const</code> member types where the resulting pointer was
  475. thrown away is undefined behaviour. As of the resolution of a national body
  476. comment, this is no longer the case, and now Outcome is free of this particular
  477. UB for C++ 20 onwards.</p>
  478. <p>This still affects C++ before 20, though no major compiler is affected. Still,
  479. if you wish to avoid UB, don&rsquo;t use <code>const</code> types within Outcome types (or any
  480. <code>optional&lt;T&gt;</code>, or <code>vector&lt;T&gt;</code> or any STL container type for that matter).</p>
  481. <h3 id="more-detail">More detail</h3>
  482. <p>Before the C++ 14 standard, placement new into storage which used to contain
  483. a const type was straight out always undefined behaviour, period. Thus all use of
  484. placement new within a <code>result&lt;const_containing_type&gt;</code>, or indeed an <code>optional&lt;const_containing_type&gt;</code>, is always
  485. undefined behaviour before C++ 14. From <code>[basic.life]</code> for the C++ 11 standard:</p>
  486. <blockquote>
  487. <p>Creating a new object at the storage location that a const object with static,
  488. thread, or automatic storage duration occupies or, at the storage location
  489. that such a const object used to occupy before its lifetime ended results
  490. in undefined behavior.</p>
  491. </blockquote>
  492. <p>This being excessively restrictive, from C++ 14 onwards, <code>[basic_life]</code> now states:</p>
  493. <blockquote>
  494. <p>If, after the lifetime of an object has ended and before the storage which
  495. the object occupied is reused or released, a new object is created at the
  496. storage location which the original object occupied, a pointer that
  497. pointed to the original object, a reference that referred to the original
  498. object, or the name of the original object will automatically refer to the
  499. new object and, once the lifetime of the new object has started, can be
  500. used to manipulate the new object, if:</p>
  501. <p>— the storage for the new object exactly overlays the storage location which
  502. the original object occupied, and</p>
  503. <p>— the new object is of the same type as the original object (ignoring the
  504. top-level cv-qualifiers), and</p>
  505. <p>— the type of the original object is not const-qualified, and, if a class type,
  506. does not contain any non-static data member whose type is const-qualified
  507. or a reference type, and</p>
  508. <p>— neither the original object nor the new object is a potentially-overlapping
  509. subobject</p>
  510. </blockquote>
  511. <p>Leaving aside my personal objections to giving placement new of non-const
  512. non-reference types magical pointer renaming powers, the upshot is that if
  513. you want defined behaviour for placement new of types containing const types
  514. or references, you must store the pointer returned by placement new, and use
  515. that pointer for all further reference to the newly created object. This
  516. obviously adds eight bytes of storage to a <code>result&lt;const_containing_type&gt;</code>, which is highly
  517. undesirable given all the care and attention paid to keeping it small. The alternative
  518. is to use
  519. <a href="https://en.cppreference.com/w/cpp/utility/launder" class="api-reference" target="_blank"><i class="fa fa-book" aria-hidden="true"></i> <code>std::launder</code></a>
  520. , which was added in C++ 17, to &lsquo;launder&rsquo;
  521. the storage into which we placement new before each and every use of that
  522. storage. This forces the compiler to reload the object stored by placement
  523. new on every occasion, and not assume it can be constant propagated, which
  524. impacts codegen quality.</p>
  525. <p>As mentioned above, this issue (in so far as it applies to types containing
  526. user supplied <code>T</code> which might be <code>const</code>) has been resolved as of C++ 20 onwards,
  527. and it is extremely unlikely that any C++ compiler will act on any UB here in
  528. C++ 17 or 14 given how much of STL containers would break.</p>
  529. </div><p><small>Last revised: November 15, 2019 at 15:43:29 UTC</small></p>
  530. <hr>
  531. <div class="spirit-nav">
  532. <a accesskey="p" href="./reference/functions/try_throw_std_exception_from_error.html"><img src="./images/prev.png" alt="Prev"></a>
  533. <a accesskey="u" href="./index.html"><img src="./images/up.png" alt="Up"></a>
  534. <a accesskey="h" href="./index.html"><img src="./images/home.png" alt="Home"></a><a accesskey="n" href="./videos.html"><img src="./images/next.png" alt="Next"></a></div></body>
  535. </html>