• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &ndash; the input string is empty,</li>
27<li><code>IllegalChar</code> &ndash; input contains characters that are not digits,</li>
28<li><code>TooLong</code> &ndash; 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">&lt;boost/system/error_code.hpp&gt;  // bring in boost::system::error_code et al</span><span class="cp">
32</span><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
33</span><span class="cp">#include</span> <span class="cpf">&lt;string&gt;  // 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">&lt;&gt;</span> <span class="k">struct</span> <span class="n">is_error_code_enum</span><span class="o">&lt;</span><span class="n">ConversionErrc</span><span class="o">&gt;</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">&#34;ConversionError&#34;</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">&lt;</span><span class="n">ConversionErrc</span><span class="o">&gt;</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">&#34;conversion successful&#34;</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">&#34;converting empty string&#34;</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">&#34;got non-digit char when converting to a number&#34;</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">&#34;the number would not fit into memory&#34;</span><span class="p">;</span>
77      <span class="k">default</span><span class="o">:</span>
78        <span class="k">return</span> <span class="s">&#34;unknown&#34;</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">&lt;</span><span class="n">ConversionErrc</span><span class="o">&gt;</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">&amp;</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">&lt;</span><span class="kt">int</span><span class="o">&gt;</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">&lt;&lt;</span> <span class="s">&#34;ConversionErrc::IllegalChar is printed by boost::system::error_code as &#34;</span>
127    <span class="o">&lt;&lt;</span> <span class="n">ec</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; with explanatory message &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">ec</span><span class="p">.</span><span class="n">message</span><span class="p">()</span> <span class="o">&lt;&lt;</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">&lt;&lt;</span> <span class="s">&#34;ec is equivalent to boost::system::errc::invalid_argument = &#34;</span>
131    <span class="o">&lt;&lt;</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">&lt;&lt;</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">&lt;&lt;</span> <span class="s">&#34;ec is equivalent to boost::system::errc::result_out_of_range = &#34;</span>
133    <span class="o">&lt;&lt;</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">&lt;&lt;</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&rsquo;d need to define a print routine
150for any custom error code you&rsquo;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&lt;&gt;</code> or <code>outcome&lt;&gt;</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&rsquo;s success by returning <code>MyEnum::Success</code>. This is because <code>error_code</code>&rsquo;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&rsquo;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 &#43;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