Remove "explicit" from Endian type constructors. Rationale: Having to write "cntr.insert(big_int32_t(value))" instead of "cntr.insert(value)" gets old fast when you are writing application code and the use case arises more or less continuously. Additionally, the use of an endian type is an implementation detail that should not leak into the application code that needs to create values of the type. Furthermore, the ambiguities that caused the constructors to be made explicit no longer occur; they were eliminated when BOOST_MINIMAL_INTEGER_COVER_OPERATORS was introduced to removed a dependency on boost/operators.hpp. If an ambiguity does arise, it is easy to clear via a static_cast or a function-style cast.

This commit is contained in:
Beman
2013-09-06 10:36:54 -04:00
parent 22728f62e2
commit d339470e6e
4 changed files with 79 additions and 52 deletions

View File

@@ -76,7 +76,7 @@
</table>
<h2><a name="Introduction">Introduction</a></h2>
<p>Header <a href="../include/boost/endian/types.hpp">boost/endian/types.hpp</a>
provides integer and floating point binary types with explicit control over
provides integer and floating point binary types with control over
byte order, value type, size, and alignment. Typedefs provide easy-to-use names
for common configurations.</p>
<p>These types provide portable byte-holders for integer data, independent of
@@ -102,7 +102,7 @@ arithmetic operators are <code>+</code>, <code>+=</code>, <code>-</code>, <code>
<code>&gt;&gt;=</code>. Binary relational operators are <code>==</code>, <code>!=</code>,
<code>&lt;</code>, <code>&lt;=</code>, <code>&gt;</code>, <code>&gt;=</code>.</p>
<p>Automatic implicit conversion to the underlying value type is provided. An
explicit conversion constructor from the underlying value type is provided. </p>
conversion constructor from the underlying value type is provided. </p>
<h2><a name="Example">Example</a></h2>
<p>The <a href="../example/endian_example.cpp">endian_example.cpp</a> program writes a
binary file containing four byte big-endian and little-endian integers:</p>
@@ -361,13 +361,14 @@ usual operations on integers are supplied.</p>
// if BOOST_ENDIAN_FORCE_PODNESS is defined &amp;&amp; C++11 POD's are not
// available then these two constructors will not be present
<a href="#endian">endian</a>() noexcept = default;
explicit <a href="#explicit-endian">endian</a>(T v) noexcept;
<a href="#explicit-endian">endian</a>(T v) noexcept;
endian&amp; <a href="#operator-eq">operator=</a>(T v) noexcept;
<a href="#operator-T">operator T</a>() const noexcept;
const char* <a href="#data">data</a>() const noexcept;
// arithmetic operations; additional operators provided by value_type
// arithmetic operations
// note that additional operations are provided by the value_type
value_type operator+(const endian&amp; x) noexcept;
endian&amp; operator+=(endian&amp; x, value_type y) noexcept;
endian&amp; operator-=(endian&amp; x, value_type y) noexcept;
@@ -387,6 +388,7 @@ usual operations on integers are supplied.</p>
endian operator--(endian&amp; x, int) noexcept;
};
// aligned big endian floating point types
typedef endian&lt;order::big, float, 32, align::yes&gt; big_align_float32_t;
typedef endian&lt;order::big, double, 64, align::yes&gt; big_align_float64_t;
@@ -423,7 +425,7 @@ usual operations on integers are supplied.</p>
typedef endian&lt;order::little, uint64_t, 64, align::yes&gt; little_align_uint64_t;
// aligned native endian typedefs are not provided because
// &lt;cstdint&gt; types are superior for this use case
// &lt;cstdint&gt; types are superior for that use case
// unaligned big endian signed integer types
typedef endian&lt;order::big, int_least8_t, 8&gt; big_int8_t;
@@ -488,28 +490,30 @@ usual operations on integers are supplied.</p>
} // namespace endian
} // namespace boost</pre>
<h3><a name="Members">Members</a></h3>
<p><code><a name="endian">endian</a>() = default;&nbsp; // C++03: endian(){}</code></p>
<div dir="ltr">
<pre><code><a name="endian">endian</a>() = default; // C++03: endian(){}</code></pre>
</div>
<blockquote>
<p><i>Effects:</i> Constructs an object of type <code>endian&lt;E, T, n_bits, A&gt;</code>.</p>
</blockquote>
<p><code><a name="explicit-endian">explicit endian</a>(T v);</code></p>
<pre><code><a name="explicit-endian">endian</a>(T v);</code></pre>
<blockquote>
<p><i>Effects:</i> Constructs an object of type <code>endian&lt;E, T, n_bits, A&gt;</code>.</p>
<p><i>Postcondition:</i> <code>x == v,</code> where <code>x</code> is the
constructed object.</p>
</blockquote>
<p><code>endian&amp; <a name="operator-eq">operator=</a>(T v);</code></p>
<pre><code>endian&amp; <a name="operator-eq">operator=</a>(T v);</code></pre>
<blockquote>
<p><i>Postcondition:</i> <code>x == v,</code> where <code>x</code> is the
constructed object.</p>
<p><i>Returns:</i> <code>*this</code>.</p>
</blockquote>
<p><code><a name="operator-T">operator T</a>() const;</code></p>
<pre><code><a name="operator-T">operator T</a>() const;</code></pre>
<blockquote>
<p><i>Returns:</i> The current value stored in <code>*this</code>, converted to
<code>value_type</code>.</p>
</blockquote>
<p><code>const char* <a name="data">data</a>() const;</code></p>
<pre><code>const char* <a name="data">data</a>() const;</code></pre>
<blockquote>
<p><i>Returns:</i> A pointer to the first byte of the endian binary value stored
in <code>*this</code>.</p>
@@ -617,7 +621,7 @@ differs from endian representation size. Vicente Botet and other reviewers
suggested supporting floating point types.</p>
<hr>
<p>Last revised:
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->31 August, 2013<!--webbot bot="Timestamp" endspan i-checksum="34505" --></p>
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->06 September, 2013<!--webbot bot="Timestamp" endspan i-checksum="39344" --></p>
<p>© Copyright Beman Dawes, 2006-2009, 2013</p>
<p>Distributed under the Boost Software License, Version 1.0. See
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>

View File

@@ -63,6 +63,12 @@
# define BOOST_ENDIAN_NO_CTORS
# endif
# ifndef BOOST_ENDIAN_EXPLICIT_CTORS
# define BOOST_ENDIAN_EXPLICIT_OPT
# else
# define BOOST_ENDIAN_EXPLICIT_OPT explicit
# endif
//---------------------------------- synopsis ----------------------------------------//
namespace boost
@@ -298,7 +304,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -331,7 +337,7 @@ namespace endian
typedef float value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(value_type val) BOOST_NOEXCEPT
{ detail::big_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
@@ -356,7 +362,7 @@ namespace endian
typedef double value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(value_type val) BOOST_NOEXCEPT
{ detail::big_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
@@ -381,7 +387,7 @@ namespace endian
typedef float value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(value_type val) BOOST_NOEXCEPT
{ detail::little_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
@@ -406,7 +412,7 @@ namespace endian
typedef double value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(value_type val) BOOST_NOEXCEPT
{ detail::little_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
@@ -432,7 +438,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -467,9 +473,9 @@ namespace endian
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
# ifdef BOOST_BIG_ENDIAN
explicit endian(T val) BOOST_NOEXCEPT { detail::store_big_endian<T, n_bits/8>(m_value, val); }
BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT { detail::store_big_endian<T, n_bits/8>(m_value, val); }
# else
explicit endian(T val) BOOST_NOEXCEPT { detail::store_little_endian<T, n_bits/8>(m_value, val); }
BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT { detail::store_little_endian<T, n_bits/8>(m_value, val); }
# endif
# endif
# ifdef BOOST_BIG_ENDIAN
@@ -501,7 +507,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -540,7 +546,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val) BOOST_NOEXCEPT
BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )

View File

@@ -14,10 +14,11 @@ project
test-suite "endian"
:
[ run endian_test.cpp
[ run endian_test.cpp # sources
: # command line
: # input files
: # requirements
: # target name
]
[ run endian_operations_test.cpp ]
[ run endian_in_union_test.cpp ]

View File

@@ -42,6 +42,8 @@
# pragma warning( disable : 4389 ) // signed/unsigned mismatch
#endif
#define BOOST_ENDIAN_LOG
#include <boost/endian/types.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/detail/lightweight_test.hpp>
@@ -341,6 +343,8 @@ void op_test()
#endif
}
void f_big_int32_t(be::big_int32_t) {}
// main ------------------------------------------------------------------------------//
int cpp_main(int, char * [])
@@ -364,6 +368,13 @@ int cpp_main(int, char * [])
be::little_uint16_t little_u(10);
be::big_int64_t result;
// this is the use case that is so irritating that it caused the endian
// constructors to be made non-explicit
std::clog << "\nf(1234) where f(big_int32_t)\n";
f_big_int32_t(1234);
std::clog << "\nresult = big\n";
result = big;
std::clog << "\nresult = +big\n";
result = +big;
@@ -417,21 +428,26 @@ int cpp_main(int, char * [])
result = 5 * 10;
std::clog << "\n";
be::endian_log = false;
// test from Roland Schwarz that detected ambiguities
// test from Roland Schwarz that detected ambiguities; these ambiguities
// were eliminated by BOOST_MINIMAL_INTEGER_COVER_OPERATORS
unsigned u;
be::little_uint32_t u1;
be::little_uint32_t u2;
u = 1;
u = 9;
u1 = 1;
std::clog << "\nu2 = u1 + u\n";
u2 = u1 + u;
std::clog << "\n";
// one more wrinkle
be::little_uint16_t u3(3);
u3 = 3;
std::clog << "\nu2 = u1 + u3\n";
u2 = u1 + u3;
std::clog << "\n";
be::endian_log = false;
// perform the indicated test on ~60*60 operand types