From d339470e6e90e52ca3cd595c2387b2585f3774dc Mon Sep 17 00:00:00 2001 From: Beman Date: Fri, 6 Sep 2013 10:36:54 -0400 Subject: [PATCH] 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. --- doc/types.html | 78 +++++++++++++++++---------------- include/boost/endian/types.hpp | 26 ++++++----- test/Jamfile.v2 | 3 +- test/endian_operations_test.cpp | 24 ++++++++-- 4 files changed, 79 insertions(+), 52 deletions(-) diff --git a/doc/types.html b/doc/types.html index 18720a2..c982ef0 100644 --- a/doc/types.html +++ b/doc/types.html @@ -76,7 +76,7 @@

Introduction

Header boost/endian/types.hpp -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.

These types provide portable byte-holders for integer data, independent of @@ -102,7 +102,7 @@ arithmetic operators are +, +=, -, >>=. Binary relational operators are ==, !=, <, <=, >, >=.

Automatic implicit conversion to the underlying value type is provided. An -explicit conversion constructor from the underlying value type is provided.

+conversion constructor from the underlying value type is provided.

Example

The endian_example.cpp program writes a binary file containing four byte big-endian and little-endian integers:

@@ -361,13 +361,14 @@ usual operations on integers are supplied.

// if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 POD's are not // available then these two constructors will not be present endian() noexcept = default; - explicit endian(T v) noexcept; + endian(T v) noexcept; endian& operator=(T v) noexcept; operator T() const noexcept; const char* data() 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& x) noexcept; endian& operator+=(endian& x, value_type y) noexcept; endian& operator-=(endian& x, value_type y) noexcept; @@ -387,43 +388,44 @@ usual operations on integers are supplied.

endian operator--(endian& x, int) noexcept; }; - typedef endian<order::big, float, 32, align::yes> big_align_float32_t; - typedef endian<order::big, double, 64, align::yes> big_align_float64_t; + // aligned big endian floating point types + typedef endian<order::big, float, 32, align::yes> big_align_float32_t; + typedef endian<order::big, double, 64, align::yes> big_align_float64_t; - // aligned little endian floating point types - typedef endian<order::little, float, 32, align::yes> little_align_float32_t; - typedef endian<order::little, double, 64, align::yes> little_align_float64_t; + // aligned little endian floating point types + typedef endian<order::little, float, 32, align::yes> little_align_float32_t; + typedef endian<order::little, double, 64, align::yes> little_align_float64_t; - // unaligned big endian floating point types - typedef endian<order::big, float, 32, align::no> big_float32un_t; - typedef endian<order::big, double, 64, align::no> big_float64un_t; + // unaligned big endian floating point types + typedef endian<order::big, float, 32, align::no> big_float32un_t; + typedef endian<order::big, double, 64, align::no> big_float64un_t; // unaligned little endian floating point types - typedef endian<order::little, float, 32, align::no> little_float32un_t; - typedef endian<order::little, double, 64, align::no> little_float64un_t; + typedef endian<order::little, float, 32, align::no> little_float32un_t; + typedef endian<order::little, double, 64, align::no> little_float64un_t; // aligned big endian signed integer types - typedef endian<order::big, int16_t, 16, align::yes> big_align_int16_t; - typedef endian<order::big, int32_t, 32, align::yes> big_align_int32_t; - typedef endian<order::big, int64_t, 64, align::yes> big_align_int64_t; + typedef endian<order::big, int16_t, 16, align::yes> big_align_int16_t; + typedef endian<order::big, int32_t, 32, align::yes> big_align_int32_t; + typedef endian<order::big, int64_t, 64, align::yes> big_align_int64_t; - // aligned big endian unsigned integer types - typedef endian<order::big, uint16_t, 16, align::yes> big_align_uint16_t; - typedef endian<order::big, uint32_t, 32, align::yes> big_align_uint32_t; - typedef endian<order::big, uint64_t, 64, align::yes> big_align_uint64_t; + // aligned big endian unsigned integer types + typedef endian<order::big, uint16_t, 16, align::yes> big_align_uint16_t; + typedef endian<order::big, uint32_t, 32, align::yes> big_align_uint32_t; + typedef endian<order::big, uint64_t, 64, align::yes> big_align_uint64_t; - // aligned little endian signed integer types - typedef endian<order::little, int16_t, 16, align::yes> little_align_int16_t; - typedef endian<order::little, int32_t, 32, align::yes> little_align_int32_t; - typedef endian<order::little, int64_t, 64, align::yes> little_align_int64_t; + // aligned little endian signed integer types + typedef endian<order::little, int16_t, 16, align::yes> little_align_int16_t; + typedef endian<order::little, int32_t, 32, align::yes> little_align_int32_t; + typedef endian<order::little, int64_t, 64, align::yes> little_align_int64_t; - // aligned little endian unsigned integer types - typedef endian<order::little, uint16_t, 16, align::yes> little_align_uint16_t; - typedef endian<order::little, uint32_t, 32, align::yes> little_align_uint32_t; - typedef endian<order::little, uint64_t, 64, align::yes> little_align_uint64_t; + // aligned little endian unsigned integer types + typedef endian<order::little, uint16_t, 16, align::yes> little_align_uint16_t; + typedef endian<order::little, uint32_t, 32, align::yes> little_align_uint32_t; + typedef endian<order::little, uint64_t, 64, align::yes> little_align_uint64_t; - // aligned native endian typedefs are not provided because - // <cstdint> types are superior for this use case + // aligned native endian typedefs are not provided because + // <cstdint> types are superior for that use case // unaligned big endian signed integer types typedef endian<order::big, int_least8_t, 8> big_int8_t; @@ -488,28 +490,30 @@ usual operations on integers are supplied.

} // namespace endian } // namespace boost

Members

-

endian() = default;  // C++03: endian(){}

+
+
endian() = default;  // C++03: endian(){}
+

Effects: Constructs an object of type endian<E, T, n_bits, A>.

-

explicit endian(T v);

+
endian(T v);

Effects: Constructs an object of type endian<E, T, n_bits, A>.

Postcondition: x == v, where x is the constructed object.

-

endian& operator=(T v);

+
endian& operator=(T v);

Postcondition: x == v, where x is the constructed object.

Returns: *this.

-

operator T() const;

+
operator T() const;

Returns: The current value stored in *this, converted to value_type.

-

const char* data() const;

+
const char* data() const;

Returns: A pointer to the first byte of the endian binary value stored in *this.

@@ -617,7 +621,7 @@ differs from endian representation size. Vicente Botet and other reviewers suggested supporting floating point types.


Last revised: -31 August, 2013

+06 September, 2013

© Copyright Beman Dawes, 2006-2009, 2013

Distributed under the Boost Software License, Version 1.0. See www.boost.org/ LICENSE_1_0.txt

diff --git a/include/boost/endian/types.hpp b/include/boost/endian/types.hpp index 82c7dd8..95aa191 100644 --- a/include/boost/endian/types.hpp +++ b/include/boost/endian/types.hpp @@ -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(m_value, val); } + BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT { detail::store_big_endian(m_value, val); } # else - explicit endian(T val) BOOST_NOEXCEPT { detail::store_little_endian(m_value, val); } + BOOST_ENDIAN_EXPLICIT_OPT endian(T val) BOOST_NOEXCEPT { detail::store_little_endian(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 ) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 150c052..23f94f8 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -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 ] diff --git a/test/endian_operations_test.cpp b/test/endian_operations_test.cpp index 42315ac..7d225c6 100644 --- a/test/endian_operations_test.cpp +++ b/test/endian_operations_test.cpp @@ -42,6 +42,8 @@ # pragma warning( disable : 4389 ) // signed/unsigned mismatch #endif +#define BOOST_ENDIAN_LOG + #include #include #include @@ -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