mirror of
https://github.com/boostorg/convert.git
synced 2026-01-26 18:32:56 +00:00
194 lines
22 KiB
HTML
194 lines
22 KiB
HTML
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title>User Interface Signature</title>
|
||
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
||
<link rel="home" href="../../index.html" title="Chapter 1. Boost.Convert 2.0">
|
||
<link rel="up" href="../design_notes.html" title="Design Notes">
|
||
<link rel="prev" href="converter_signature.html" title="Converter Signature">
|
||
<link rel="next" href="../supporting_tools.html" title="Supporting Tools">
|
||
</head>
|
||
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="converter_signature.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../design_notes.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="../supporting_tools.html"><img src="../../images/next.png" alt="Next"></a>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="boost_convert.design_notes.user_interface_signature"></a><a class="link" href="user_interface_signature.html" title="User Interface Signature">User
|
||
Interface Signature</a>
|
||
</h3></div></div></div>
|
||
<p>
|
||
The first attempt to accommodate the User Requirements might result in the
|
||
following fairly conventional interface:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">></span> <span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#1</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">></span> <span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">fallback</span><span class="special">);</span> <span class="comment">//#2</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">></span> <span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">Out</span><span class="special">&</span> <span class="identifier">result_out</span><span class="special">,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#3</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">></span> <span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">Out</span><span class="special">&</span> <span class="identifier">result_out</span><span class="special">,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">fallback</span><span class="special">);</span> <span class="comment">//#4</span>
|
||
</pre>
|
||
<p>
|
||
with the following behavior:
|
||
</p>
|
||
<div class="orderedlist"><ol class="orderedlist" type="1">
|
||
<li class="listitem">
|
||
returns the result or throws on failure (<span class="emphasis"><em>R3a</em></span>, <span class="emphasis"><em>R4</em></span>);
|
||
</li>
|
||
<li class="listitem">
|
||
does not throw, returns the result or the provided fallback (<span class="emphasis"><em>R3b</em></span>,
|
||
<span class="emphasis"><em>R5</em></span>, <span class="emphasis"><em>R5c</em></span> but not <span class="emphasis"><em>R5a</em></span>);
|
||
</li>
|
||
<li class="listitem">
|
||
does not throw, writes the result to <code class="computeroutput"><span class="identifier">result_out</span></code>
|
||
(when successful), returns indication of success or failure (<span class="emphasis"><em>R3b</em></span>,
|
||
<span class="emphasis"><em>R5</em></span>, <span class="emphasis"><em>R5a</em></span> but not <span class="emphasis"><em>R5c</em></span>);
|
||
</li>
|
||
<li class="listitem">
|
||
does not throw, writes the result to <code class="computeroutput"><span class="identifier">result_out</span></code>
|
||
(when successful) or the provided fallback, returns indication of success
|
||
or failure (<span class="emphasis"><em>R3b</em></span>, <span class="emphasis"><em>R5</em></span>, <span class="emphasis"><em>R5c</em></span>
|
||
and <span class="emphasis"><em>R5a</em></span>).
|
||
</li>
|
||
</ol></div>
|
||
<p>
|
||
The #3 and #4 signatures are special as they, in fact, return two things
|
||
-- the actual result (written into the <code class="computeroutput"><span class="identifier">result_out</span></code>)
|
||
and the indication of success or failure (returned by the functions). Given
|
||
that a reference to <code class="computeroutput"><span class="identifier">result_out</span></code>
|
||
is passed in, the actual <code class="computeroutput"><span class="identifier">result_out</span></code>
|
||
instance is constructed (storage allocated and initialized) outside the function
|
||
calls.
|
||
</p>
|
||
<p>
|
||
Similar to the scenario described in the <a class="link" href="converter_signature.html" title="Converter Signature">Converter
|
||
Signature</a> section that results in an additional and unnecessary overhead.
|
||
Indeed, if the conversion operation succeeds, then the initialization value
|
||
is overridden (with the actual result), if it fails, then the value is either
|
||
overridden still (with the fallback) or is meaningless.
|
||
</p>
|
||
<p>
|
||
To avoid the overhead we might again (as in the <a class="link" href="converter_signature.html" title="Converter Signature">Converter
|
||
Signature</a> section) deploy <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code>
|
||
and to change the signatures to
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">>&,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#3</span>
|
||
<span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">>&,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#4</span>
|
||
</pre>
|
||
<p>
|
||
Now, when we look at #3, we can see that the indication of success or failure
|
||
is duplicated. Namely, it is returned from the function and is encapsulated
|
||
in <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">></span></code>.
|
||
Consequently, #3 can be further simplified to
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">>&,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#3</span>
|
||
</pre>
|
||
<p>
|
||
or expressed more idiomatically (in C++) as:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">></span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#3</span>
|
||
</pre>
|
||
<p>
|
||
So far, we have arrived to the following set
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#1</span>
|
||
<span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#2</span>
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">></span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#3</span>
|
||
<span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">>&,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&);</span> <span class="comment">//#4</span>
|
||
</pre>
|
||
<p>
|
||
which as a whole looks quite ugly and, in fact, does not even compile as
|
||
#1 clashes with #3. The good thing though is that <span class="emphasis"><em>functionally</em></span>
|
||
#1 and #2 are not needed anymore as they are duplicates of the following
|
||
#3 deployments:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">Out</span> <span class="identifier">out1</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span> <span class="comment">// #3 with #1 behavior</span>
|
||
<span class="identifier">Out</span> <span class="identifier">out2</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback</span><span class="special">);</span> <span class="comment">// #3 with #2 behavior</span>
|
||
</pre>
|
||
<p>
|
||
Again, we are not discussing aesthetic aspects of the interface (or syntactic
|
||
sugar some might say, which might be very subjective). Instead, we are focusing
|
||
on the <span class="emphasis"><em>functional completeness</em></span> and so far we manage
|
||
to maintain the same <span class="emphasis"><em>functional completeness</em></span> with <span class="emphasis"><em>less</em></span>.
|
||
</p>
|
||
<p>
|
||
Turns out, with a bit of effort, we can get away without the most complex
|
||
one -- #4 -- as well:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">></span> <span class="identifier">out</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">);</span>
|
||
<span class="keyword">bool</span> <span class="identifier">out_success</span> <span class="special">=</span> <span class="identifier">out</span> <span class="special">?</span> <span class="keyword">true</span> <span class="special">:</span> <span class="keyword">false</span><span class="special">;</span>
|
||
<span class="identifier">Out</span> <span class="identifier">out_value</span> <span class="special">=</span> <span class="identifier">out</span><span class="special">.</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
So, ultimately we arrive to one and only
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">></span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&);</span>
|
||
</pre>
|
||
<p>
|
||
The important qualities of the API are that it is <span class="emphasis"><em>functionally-complete</em></span>
|
||
and the <span class="emphasis"><em>most efficient way</em></span> to deploy the chosen converter
|
||
signature (see the <a class="link" href="converter_signature.html" title="Converter Signature">Converter
|
||
Signature</a> section). Namely, the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">()</span></code> interface is routinely optimized out (elided)
|
||
when deployed as
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">Out</span><span class="special">></span> <span class="identifier">out</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
The API has several deployment-related advantages. First, it says exactly
|
||
what it does. Given a conversion request is only a <span class="emphasis"><em>request</em></span>,
|
||
the API returns <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code> essentially saying "I'll
|
||
try but I might fail. Proceed as you find appropriate.". Honest and
|
||
simple. I prefer it to "I'll try. I might fail but you do not want to
|
||
know about it." or "I'll try. If I fail, you die." or variations
|
||
along these lines. :-)
|
||
</p>
|
||
<p>
|
||
On a more serious note though the interface allows for batched conveyor-style
|
||
conversions. Namely, attempting to convert several values, in sequence, storing
|
||
the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code> results and, then, analyzing/validating
|
||
them (without losing the information if each individual conversion was successful
|
||
or not) in some semi-automated way.
|
||
</p>
|
||
<p>
|
||
Again, that API does not have to be the only API <span class="emphasis"><em>Boost.Convert</em></span>
|
||
provides. However, that API is the only <span class="emphasis"><em>essential</em></span> API.
|
||
Other APIs are relatively easily derived from it. For example,
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">></span>
|
||
<span class="identifier">Out</span>
|
||
<span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">in</span><span class="special">,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">fallback</span><span class="special">)</span> <span class="comment">//#2</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
Given that it is extremely difficult (if not impossible) to come up with
|
||
a library API that could please everyone, we might as well settle on the
|
||
<span class="emphasis"><em>essential</em></span> API and let the users build their own APIs
|
||
(as in the example above) to satisfy their aesthetic preferences.
|
||
</p>
|
||
<p>
|
||
Still, it needs to be acknowledged that <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code>
|
||
is a fairly new concept and some people are reluctant using it or find its
|
||
deployment unreasonably complicating. Consequently, <span class="emphasis"><em>Boost.Convert</em></span>
|
||
provides an alternative (more conventional) interface:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">Out</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Converter</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">fallback_value</span><span class="special">);</span>
|
||
<span class="identifier">Out</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Converter</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Functor</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">fallback_functor</span><span class="special">);</span>
|
||
<span class="identifier">Out</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">Converter</span> <span class="keyword">const</span><span class="special">&,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">throw_on_failure</span><span class="special">);</span>
|
||
</pre>
|
||
</div>
|
||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||
<td align="left"></td>
|
||
<td align="right"><div class="copyright-footer">Copyright © 2009-2022 Vladimir
|
||
Batov<p>
|
||
Distributed under the Boost Software License, Version 1.0. See copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>.
|
||
</p>
|
||
</div></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="converter_signature.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../design_notes.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="../supporting_tools.html"><img src="../../images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|