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>Plugging a library into boost::system::error_code - 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 8<link rel="icon" href="../images/favicon.ico" type="image/ico"/> 9<body><div class="spirit-nav"> 10<a accesskey="p" href="../motivation/plug_error_code.html"><img src="../images/prev.png" alt="Prev"></a> 11 <a accesskey="u" href="../motivation.html"><img src="../images/up.png" alt="Up"></a> 12 <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../motivation/narrow_contract.html"><img src="../images/next.png" alt="Next"></a></div><div id="content"> 13 <div class="titlepage"><div><div><h1 style="clear: both">Plugging a library into boost::system::error_code</h1></div></div></div> 14 <p><a href="../motivation/plug_error_code.html">See here for this guide, but for <code>std::error_code</code></a>.</p> 15 16<p>This section illustrates how you can hook into the <code>boost::system::error_code</code> system from 17the Boost in order to work with your own set of error codes. As is usually 18the case in C++, doing this is straightforward but requires typing boilerplate 19to tell Boost.System about your custom error type. This is not part of Outcome library, 20but we still provide this short guide here, because how to do this is not well documented [1].</p> 21 22<p>Suppose you want to report all reasons for failure in converting a <code>std::string</code> to a non-negative <code>int</code>. 23The list is:</p> 24 25<ul> 26<li><code>EmptyString</code> – the input string is empty,</li> 27<li><code>IllegalChar</code> – input contains characters that are not digits,</li> 28<li><code>TooLong</code> – input represents a number, but this number would not fit into a variable of type <code>int</code>.</li> 29</ul> 30 31<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="cp">#include</span> <span class="cpf"><boost/system/error_code.hpp> // bring in boost::system::error_code et al</span><span class="cp"> 32</span><span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"> 33</span><span class="cp">#include</span> <span class="cpf"><string> // for string printing</span><span class="cp"> 34</span><span class="cp"></span> 35<span class="c1">// This is the custom error code enum 36</span><span class="c1"></span><span class="k">enum</span> <span class="k">class</span><span class="err"> </span><span class="nc">ConversionErrc</span> 37<span class="p">{</span> 38 <span class="n">Success</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="c1">// 0 should not represent an error 39</span><span class="c1"></span> <span class="n">EmptyString</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> 40 <span class="n">IllegalChar</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> 41 <span class="n">TooLong</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> 42<span class="p">};</span> 43 44<span class="k">namespace</span> <span class="n">boost</span> 45<span class="p">{</span> 46 <span class="k">namespace</span> <span class="n">system</span> 47 <span class="p">{</span> 48 <span class="c1">// Tell the C++ 11 STL metaprogramming that enum ConversionErrc 49</span><span class="c1"></span> <span class="c1">// is registered with the standard error code system 50</span><span class="c1"></span> <span class="k">template</span> <span class="o"><></span> <span class="k">struct</span> <span class="n">is_error_code_enum</span><span class="o"><</span><span class="n">ConversionErrc</span><span class="o">></span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">true_type</span> 51 <span class="p">{</span> 52 <span class="p">};</span> 53 <span class="p">}</span> <span class="c1">// namespace system 54</span><span class="c1"></span><span class="p">}</span> <span class="c1">// namespace boost 55</span><span class="c1"></span> 56<span class="k">namespace</span> <span class="n">detail</span> 57<span class="p">{</span> 58 <span class="c1">// Define a custom error code category derived from boost::system::error_category 59</span><span class="c1"></span> <span class="k">class</span><span class="err"> </span><span class="nc">ConversionErrc_category</span> <span class="o">:</span> <span class="k">public</span> <span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">error_category</span> 60 <span class="p">{</span> 61 <span class="k">public</span><span class="o">:</span> 62 <span class="c1">// Return a short descriptive name for the category 63</span><span class="c1"></span> <span class="k">virtual</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">()</span> <span class="k">const</span> <span class="k">noexcept</span> <span class="k">override</span> <span class="k">final</span> <span class="p">{</span> <span class="k">return</span> <span class="s">"ConversionError"</span><span class="p">;</span> <span class="p">}</span> 64 <span class="c1">// Return what each enum means in text 65</span><span class="c1"></span> <span class="k">virtual</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">message</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="p">)</span> <span class="k">const</span> <span class="k">override</span> <span class="k">final</span> 66 <span class="p">{</span> 67 <span class="k">switch</span><span class="p">(</span><span class="k">static_cast</span><span class="o"><</span><span class="n">ConversionErrc</span><span class="o">></span><span class="p">(</span><span class="n">c</span><span class="p">))</span> 68 <span class="p">{</span> 69 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">Success</span><span class="p">:</span> 70 <span class="k">return</span> <span class="s">"conversion successful"</span><span class="p">;</span> 71 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">EmptyString</span><span class="p">:</span> 72 <span class="k">return</span> <span class="s">"converting empty string"</span><span class="p">;</span> 73 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">IllegalChar</span><span class="p">:</span> 74 <span class="k">return</span> <span class="s">"got non-digit char when converting to a number"</span><span class="p">;</span> 75 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">TooLong</span><span class="p">:</span> 76 <span class="k">return</span> <span class="s">"the number would not fit into memory"</span><span class="p">;</span> 77 <span class="k">default</span><span class="o">:</span> 78 <span class="k">return</span> <span class="s">"unknown"</span><span class="p">;</span> 79 <span class="p">}</span> 80 <span class="p">}</span> 81 <span class="c1">// OPTIONAL: Allow generic error conditions to be compared to me 82</span><span class="c1"></span> <span class="k">virtual</span> <span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">error_condition</span> <span class="n">default_error_condition</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="p">)</span> <span class="k">const</span> <span class="k">noexcept</span> <span class="k">override</span> <span class="k">final</span> 83 <span class="p">{</span> 84 <span class="k">switch</span><span class="p">(</span><span class="k">static_cast</span><span class="o"><</span><span class="n">ConversionErrc</span><span class="o">></span><span class="p">(</span><span class="n">c</span><span class="p">))</span> 85 <span class="p">{</span> 86 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">EmptyString</span><span class="p">:</span> 87 <span class="k">return</span> <span class="n">make_error_condition</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">invalid_argument</span><span class="p">);</span> 88 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">IllegalChar</span><span class="p">:</span> 89 <span class="k">return</span> <span class="n">make_error_condition</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">invalid_argument</span><span class="p">);</span> 90 <span class="k">case</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="nl">TooLong</span><span class="p">:</span> 91 <span class="k">return</span> <span class="n">make_error_condition</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">result_out_of_range</span><span class="p">);</span> 92 <span class="k">default</span><span class="o">:</span> 93 <span class="c1">// I have no mapping for this code 94</span><span class="c1"></span> <span class="k">return</span> <span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">error_condition</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="o">*</span><span class="k">this</span><span class="p">);</span> 95 <span class="p">}</span> 96 <span class="p">}</span> 97 <span class="p">};</span> 98<span class="p">}</span> <span class="c1">// namespace detail 99</span><span class="c1"></span> 100<span class="c1">// Define the linkage for this function to be used by external code. 101</span><span class="c1">// This would be the usual __declspec(dllexport) or __declspec(dllimport) 102</span><span class="c1">// if we were in a Windows DLL etc. But for this example use a global 103</span><span class="c1">// instance but with inline linkage so multiple definitions do not collide. 104</span><span class="c1"></span><span class="cp">#define THIS_MODULE_API_DECL extern inline 105</span><span class="cp"></span> 106<span class="c1">// Declare a global function returning a static instance of the custom category 107</span><span class="c1"></span><span class="n">THIS_MODULE_API_DECL</span> <span class="k">const</span> <span class="n">detail</span><span class="o">::</span><span class="n">ConversionErrc_category</span> <span class="o">&</span><span class="n">ConversionErrc_category</span><span class="p">()</span> 108<span class="p">{</span> 109 <span class="k">static</span> <span class="n">detail</span><span class="o">::</span><span class="n">ConversionErrc_category</span> <span class="n">c</span><span class="p">;</span> 110 <span class="k">return</span> <span class="n">c</span><span class="p">;</span> 111<span class="p">}</span> 112 113 114<span class="c1">// Overload the global make_error_code() free function with our 115</span><span class="c1">// custom enum. It will be found via ADL by the compiler if needed. 116</span><span class="c1"></span><span class="kr">inline</span> <span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">error_code</span> <span class="n">make_error_code</span><span class="p">(</span><span class="n">ConversionErrc</span> <span class="n">e</span><span class="p">)</span> 117<span class="p">{</span> 118 <span class="k">return</span> <span class="p">{</span><span class="k">static_cast</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="p">(</span><span class="n">e</span><span class="p">),</span> <span class="n">ConversionErrc_category</span><span class="p">()};</span> 119<span class="p">}</span> 120 121<span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> 122<span class="p">{</span> 123 <span class="c1">// Note that we can now supply ConversionErrc directly to error_code 124</span><span class="c1"></span> <span class="n">boost</span><span class="o">::</span><span class="n">system</span><span class="o">::</span><span class="n">error_code</span> <span class="n">ec</span> <span class="o">=</span> <span class="n">ConversionErrc</span><span class="o">::</span><span class="n">IllegalChar</span><span class="p">;</span> 125 126 <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"ConversionErrc::IllegalChar is printed by boost::system::error_code as "</span> 127 <span class="o"><<</span> <span class="n">ec</span> <span class="o"><<</span> <span class="s">" with explanatory message "</span> <span class="o"><<</span> <span class="n">ec</span><span class="p">.</span><span class="n">message</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> 128 129 <span class="c1">// We can compare ConversionErrc containing error codes to generic conditions 130</span><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"ec is equivalent to boost::system::errc::invalid_argument = "</span> 131 <span class="o"><<</span> <span class="p">(</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">invalid_argument</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> 132 <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"ec is equivalent to boost::system::errc::result_out_of_range = "</span> 133 <span class="o"><<</span> <span class="p">(</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">result_out_of_range</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> 134 <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> 135<span class="p">}</span> 136</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/error_code_registration.cpp#L32" class="code-snippet-url" target="_blank">View this code on Github</a></div> 137 138 139<p>This might look like a lot of extra boilerplate over simply using your custom 140error code enum directly, but look at the advantages:</p> 141 142<ol> 143<li>Any code which can speak <code>boost::system::error_code</code> can now work with errors from your 144code, AND without being recompiled.</li> 145<li><code>boost::system::system_error</code> can now wrap your custom error codes seamlessly, allowing 146your custom error code to be converted into a C++ exception <em>and back out again</em> 147without losing information.</li> 148<li><code>boost::system::error_code</code> knows how to print itself, and will print your custom error 149code without extra work from you. As usually you’d need to define a print routine 150for any custom error code you’d write anyway, there is actually very little extra 151boilerplate here.</li> 152<li>If you implement the <code>default_error_condition()</code> override, you can allow code 153exclusively written to understand <code>boost::system::errc</code> alone to examine your custom error 154code domain for equivalence to the standard error conditions, AND without being 155recompiled.</li> 156</ol> 157 158<div class="notices note" style="background: url('../images/note.png') top left no-repeat padding-box padding-box;"> 159<div class="notices heading">note</div> 160<div class="notices message"><p>This documentation recommends that when you define your custom <code>enum</code> for representing 161<code>error_code</code>s, you should always make sure that value 0 never represents an actual error: 162it should either represent a success or should not be provided at all. If you only 163intend to use your <code>enum</code> inside <code>result<></code> or <code>outcome<></code> you can just start your 164enumerations from 1. If you intend to also return <code>boost::system::error_code</code> directly from 165functions, you should probably define value 0 as success, so that you are able to 166inform about function’s success by returning <code>MyEnum::Success</code>. This is because <code>error_code</code>’s 167contextual conversion to <code>bool</code> (which some people use to check if there was an error or not) 168only checks for the numeric value of the error code (without looking at error domain (category)).</p> 169</div> 170</div> 171 172 173<p>[1]: The only documentation I’m aware of is the quite old guide by Chris Kohlhoff, founder of ASIO and the Networking TS:</p> 174 175<ul> 176<li><a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html">http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html</a></li> 177<li><a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html">http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html</a></li> 178<li><a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html">http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html</a></li> 179<li><a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-4.html">http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-4.html</a></li> 180<li><a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html">http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html</a></li> 181</ul> 182 183 184 </div><p><small>Last revised: June 21, 2019 at 22:46:55 +0100</small></p> 185<hr> 186<div class="spirit-nav"> 187<a accesskey="p" href="../motivation/plug_error_code.html"><img src="../images/prev.png" alt="Prev"></a> 188 <a accesskey="u" href="../motivation.html"><img src="../images/up.png" alt="Up"></a> 189 <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../motivation/narrow_contract.html"><img src="../images/next.png" alt="Next"></a></div></body> 190</html> 191