Skip to content

Make quantity a trivial type #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions include/boost/units/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,6 @@

#endif

#ifdef BOOST_UNITS_REQUIRE_LAYOUT_COMPATIBILITY
///INTERNAL ONLY
#define BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(a, b) BOOST_STATIC_ASSERT((sizeof(a) == sizeof(b)))
#else
///INTERNAL ONLY
#define BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(a, b)
#endif

#ifdef BOOST_UNITS_DOXYGEN

/// If defined will trigger a static assertion if quantity<Unit, T>
Expand Down
294 changes: 0 additions & 294 deletions include/boost/units/quantity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,156 +88,12 @@ struct disable_if_is_same<T, T> {};
template<class Unit,class Y>
class quantity
{
// base units are not the same as units.
BOOST_MPL_ASSERT_NOT((detail::is_base_unit<Unit>));
enum { force_instantiation_of_unit = sizeof(Unit) };
typedef void (quantity::*unspecified_null_pointer_constant_type)(int*******);
public:
typedef quantity<Unit,Y> this_type;

typedef Y value_type;
typedef Unit unit_type;

BOOST_CONSTEXPR quantity() : val_()
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

BOOST_CONSTEXPR quantity(unspecified_null_pointer_constant_type) : val_()
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

BOOST_CONSTEXPR quantity(const this_type& source) : val_(source.val_)
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

// Need to make sure that the destructor of
// Unit which contains the checking is instantiated,
// on sun.
#ifdef __SUNPRO_CC
~quantity() {
unit_type force_unit_instantiation;
}
#endif

//~quantity() { }

BOOST_CXX14_CONSTEXPR this_type& operator=(const this_type& source)
{
val_ = source.val_;

return *this;
}

#ifndef BOOST_NO_SFINAE

/// implicit conversion between value types is allowed if allowed for value types themselves
template<class YY>
BOOST_CONSTEXPR quantity(const quantity<Unit,YY>& source,
typename boost::enable_if<detail::is_non_narrowing_conversion<YY, Y> >::type* = 0) :
val_(source.value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

/// implicit conversion between value types is not allowed if not allowed for value types themselves
template<class YY>
explicit BOOST_CONSTEXPR quantity(const quantity<Unit,YY>& source,
typename boost::disable_if<detail::is_non_narrowing_conversion<YY, Y> >::type* = 0) :
val_(static_cast<Y>(source.value()))
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

#else

/// implicit conversion between value types is allowed if allowed for value types themselves
template<class YY>
BOOST_CONSTEXPR quantity(const quantity<Unit,YY>& source) :
val_(source.value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
BOOST_STATIC_ASSERT((boost::is_convertible<YY, Y>::value == true));
}

#endif

/// implicit assignment between value types is allowed if allowed for value types themselves
template<class YY>
BOOST_CXX14_CONSTEXPR this_type& operator=(const quantity<Unit,YY>& source)
{
BOOST_STATIC_ASSERT((boost::is_convertible<YY, Y>::value == true));

*this = this_type(source);

return *this;
}

#ifndef BOOST_NO_SFINAE

/// explicit conversion between different unit systems is allowed if implicit conversion is disallowed
template<class Unit2,class YY>
explicit
BOOST_CONSTEXPR quantity(const quantity<Unit2,YY>& source,
typename boost::disable_if<
mpl::and_<
//is_implicitly_convertible should be undefined when the
//units are not convertible at all
typename is_implicitly_convertible<Unit2,Unit>::type,
detail::is_non_narrowing_conversion<YY, Y>
>,
typename detail::disable_if_is_same<Unit, Unit2>::type
>::type* = 0)
: val_(conversion_helper<quantity<Unit2,YY>,this_type>::convert(source).value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
BOOST_STATIC_ASSERT((boost::is_convertible<YY,Y>::value == true));
}

/// implicit conversion between different unit systems is allowed if each fundamental dimension is implicitly convertible
template<class Unit2,class YY>
BOOST_CONSTEXPR quantity(const quantity<Unit2,YY>& source,
typename boost::enable_if<
mpl::and_<
typename is_implicitly_convertible<Unit2,Unit>::type,
detail::is_non_narrowing_conversion<YY, Y>
>,
typename detail::disable_if_is_same<Unit, Unit2>::type
>::type* = 0)
: val_(conversion_helper<quantity<Unit2,YY>,this_type>::convert(source).value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
BOOST_STATIC_ASSERT((boost::is_convertible<YY,Y>::value == true));
}

#else

/// without SFINAE we can't distinguish between explicit and implicit conversions so
/// the conversion is always explicit
template<class Unit2,class YY>
explicit BOOST_CONSTEXPR quantity(const quantity<Unit2,YY>& source)
: val_(conversion_helper<quantity<Unit2,YY>,this_type>::convert(source).value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
BOOST_STATIC_ASSERT((boost::is_convertible<YY,Y>::value == true));
}

#endif

/// implicit assignment between different unit systems is allowed if each fundamental dimension is implicitly convertible
template<class Unit2,class YY>
BOOST_CXX14_CONSTEXPR this_type& operator=(const quantity<Unit2,YY>& source)
{

BOOST_STATIC_ASSERT((is_implicitly_convertible<Unit2,unit_type>::value == true));
BOOST_STATIC_ASSERT((boost::is_convertible<YY,Y>::value == true));

*this = this_type(source);

return *this;
}

BOOST_CONSTEXPR const value_type& value() const { return val_; } ///< constant accessor to value

Expand Down Expand Up @@ -283,8 +139,6 @@ class quantity
/// Construct quantity directly from @c value_type (potentially dangerous).
static BOOST_CONSTEXPR this_type from_value(const value_type& val) { return this_type(val, 0); }

protected:
explicit BOOST_CONSTEXPR quantity(const value_type& val, int) : val_(val) { }

private:
value_type val_;
Expand All @@ -305,154 +159,6 @@ class quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(System),Y>
typedef dimensionless_type dimension_type;
typedef unit<dimension_type,system_type> unit_type;

BOOST_CONSTEXPR quantity() : val_()
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

/// construction from raw @c value_type is allowed
BOOST_CONSTEXPR quantity(value_type val) : val_(val)
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

BOOST_CONSTEXPR quantity(const this_type& source) : val_(source.val_)
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

//~quantity() { }

BOOST_CXX14_CONSTEXPR this_type& operator=(const this_type& source)
{
val_ = source.val_;

return *this;
}

#ifndef BOOST_NO_SFINAE

/// implicit conversion between value types is allowed if allowed for value types themselves
template<class YY>
BOOST_CONSTEXPR quantity(const quantity<unit<dimension_type,system_type>,YY>& source,
typename boost::enable_if<detail::is_non_narrowing_conversion<YY, Y> >::type* = 0) :
val_(source.value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

/// implicit conversion between value types is not allowed if not allowed for value types themselves
template<class YY>
explicit BOOST_CONSTEXPR quantity(const quantity<unit<dimension_type,system_type>,YY>& source,
typename boost::disable_if<detail::is_non_narrowing_conversion<YY, Y> >::type* = 0) :
val_(static_cast<Y>(source.value()))
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

#else

/// implicit conversion between value types is allowed if allowed for value types themselves
template<class YY>
BOOST_CONSTEXPR quantity(const quantity<unit<dimension_type,system_type>,YY>& source) :
val_(source.value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
BOOST_STATIC_ASSERT((boost::is_convertible<YY, Y>::value == true));
}

#endif

/// implicit assignment between value types is allowed if allowed for value types themselves
template<class YY>
BOOST_CXX14_CONSTEXPR this_type& operator=(const quantity<unit<dimension_type,system_type>,YY>& source)
{
BOOST_STATIC_ASSERT((boost::is_convertible<YY,Y>::value == true));

*this = this_type(source);

return *this;
}

#if 1

/// implicit conversion between different unit systems is allowed
template<class System2, class Y2>
BOOST_CONSTEXPR quantity(const quantity<unit<dimensionless_type, System2>,Y2>& source,
#ifdef __SUNPRO_CC
typename boost::enable_if<
boost::mpl::and_<
detail::is_non_narrowing_conversion<Y2, Y>,
detail::is_dimensionless_system<System2>
>
>::type* = 0
#else
typename boost::enable_if<detail::is_non_narrowing_conversion<Y2, Y> >::type* = 0,
typename detail::disable_if_is_same<System, System2>::type* = 0,
typename boost::enable_if<detail::is_dimensionless_system<System2> >::type* = 0
#endif
) :
val_(source.value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

/// implicit conversion between different unit systems is allowed
template<class System2, class Y2>
explicit BOOST_CONSTEXPR quantity(const quantity<unit<dimensionless_type, System2>,Y2>& source,
#ifdef __SUNPRO_CC
typename boost::enable_if<
boost::mpl::and_<
boost::mpl::not_<detail::is_non_narrowing_conversion<Y2, Y> >,
detail::is_dimensionless_system<System2>
>
>::type* = 0
#else
typename boost::disable_if<detail::is_non_narrowing_conversion<Y2, Y> >::type* = 0,
typename detail::disable_if_is_same<System, System2>::type* = 0,
typename boost::enable_if<detail::is_dimensionless_system<System2> >::type* = 0
#endif
) :
val_(static_cast<Y>(source.value()))
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

#else

/// implicit conversion between different unit systems is allowed
template<class System2, class Y2>
BOOST_CONSTEXPR quantity(const quantity<unit<dimensionless_type,homogeneous_system<System2> >,Y2>& source) :
val_(source.value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
BOOST_STATIC_ASSERT((boost::is_convertible<Y2, Y>::value == true));
}

#endif

/// conversion between different unit systems is explicit when
/// the units are not equivalent.
template<class System2, class Y2>
explicit BOOST_CONSTEXPR quantity(const quantity<unit<dimensionless_type, System2>,Y2>& source,
typename boost::disable_if<detail::is_dimensionless_system<System2> >::type* = 0) :
val_(conversion_helper<quantity<unit<dimensionless_type, System2>,Y2>, this_type>::convert(source).value())
{
BOOST_UNITS_CHECK_LAYOUT_COMPATIBILITY(this_type, Y);
}

#ifndef __SUNPRO_CC

/// implicit assignment between different unit systems is allowed
template<class System2>
BOOST_CXX14_CONSTEXPR this_type& operator=(const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(System2),Y>& source)
{
*this = this_type(source);

return *this;
}

#endif

/// implicit conversion to @c value_type is allowed
BOOST_CONSTEXPR operator value_type() const { return val_; }
Expand Down
13 changes: 13 additions & 0 deletions test/test_trivial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <type_traits>
#include <boost/units/systems/si/length.hpp>
// Remove this when https://github.com/boostorg/units/issues/60 is fixed:
#include <boost/units/systems/si/io.hpp>

using namespace boost::units;
using namespace boost::units::si;

static_assert(std::is_trivial_v<quantity<length>>);

int main() {
return 0;
}