Skip to content

Commit 8025fa5

Browse files
Disable explicit conversion for quantities of unrelated units
This fixes #36.
1 parent e895482 commit 8025fa5

File tree

5 files changed

+48
-8
lines changed

5 files changed

+48
-8
lines changed

include/boost/units/conversion.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace boost {
2020

2121
namespace units {
2222

23-
template<class From, class To>
23+
template<class From, class To, typename>
2424
struct conversion_helper;
2525

2626
#ifdef BOOST_UNITS_DOXYGEN

include/boost/units/detail/conversion_impl.hpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <boost/mpl/divides.hpp>
1717
#include <boost/preprocessor/seq/enum.hpp>
1818
#include <boost/type_traits/is_same.hpp>
19+
#include <boost/utility/enable_if.hpp>
1920

2021
#include <boost/units/heterogeneous_system.hpp>
2122
#include <boost/units/homogeneous_system.hpp>
@@ -326,15 +327,30 @@ struct conversion_impl<0>
326327
};
327328
};
328329

330+
template<typename Unit1, typename Unit2>
331+
class has_conversion_factor
332+
{
333+
typedef char yes[1];
334+
typedef char no[2];
335+
336+
template<typename T, typename U> static yes& test(char(*)[sizeof(conversion_factor(T(), U()))]);
337+
338+
template<typename, typename> static no& test(...);
339+
340+
public:
341+
enum { value = (sizeof(test<Unit1, Unit2>(0)) == sizeof(yes)) };
342+
};
343+
329344
} // namespace detail
330345

331346
/// forward to conversion_factor (intentionally allowing ADL)
332347
/// INTERNAL ONLY
333348
template<class Unit1, class T1, class Unit2, class T2>
334-
struct conversion_helper<quantity<Unit1, T1>, quantity<Unit2, T2> >
349+
struct conversion_helper<quantity<Unit1, T1>, quantity<Unit2, T2>, typename boost::enable_if_c<detail::has_conversion_factor<Unit1, Unit2>::value>::type>
335350
{
336351
/// INTERNAL ONLY
337352
typedef quantity<Unit2, T2> destination_type;
353+
338354
static BOOST_CONSTEXPR destination_type convert(const quantity<Unit1, T1>& source)
339355
{
340356
return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(Unit1(), Unit2()))));

include/boost/units/quantity.hpp

+17-5
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,22 @@ struct disable_if_is_same
7979
typedef void type;
8080
};
8181

82-
template<class T>
83-
struct disable_if_is_same<T, T> {};
82+
template<typename Quantity1, typename Quantity2>
83+
struct has_conversion_helper
84+
{
85+
typedef char yes[1];
86+
typedef char no[2];
87+
88+
template<typename T, typename U> static yes& test(char(*)[sizeof(conversion_helper<T,U>)]);
89+
90+
template<typename, typename> static no& test(...);
91+
92+
public:
93+
enum { value = (sizeof(test<Quantity1, Quantity2>(0)) == sizeof(yes)) };
94+
};
8495

8596
}
86-
97+
8798
/// class declaration
8899
template<class Unit,class Y>
89100
class quantity
@@ -178,9 +189,10 @@ class quantity
178189
#ifndef BOOST_NO_SFINAE
179190

180191
/// explicit conversion between different unit systems is allowed if implicit conversion is disallowed
181-
template<class Unit2,class YY>
192+
template<class Unit2,class YY>
182193
explicit
183-
BOOST_CONSTEXPR quantity(const quantity<Unit2,YY>& source,
194+
BOOST_CONSTEXPR quantity(const quantity<Unit2,YY>& source,
195+
typename boost::enable_if_c<detail::has_conversion_helper<quantity<Unit2,YY>,this_type>::value>::type* = 0,
184196
typename boost::disable_if<
185197
mpl::and_<
186198
//is_implicitly_convertible should be undefined when the

include/boost/units/units_fwd.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ template<class T> struct is_quantity;
5656
template<class T,class Dim> struct is_quantity_of_dimension;
5757
template<class T,class System> struct is_quantity_of_system;
5858

59-
template<class From,class To> struct conversion_helper;
59+
template<class From,class To, typename = void> struct conversion_helper;
6060

6161
template<class T> std::string to_string(const T&);
6262
template<class T> std::string name_string(const T&);

test/test_conversion.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ Test conversion between quantities.
2424
#include <boost/units/quantity.hpp>
2525
#include <boost/units/systems/si.hpp>
2626
#include <boost/units/systems/cgs.hpp>
27+
#include <boost/units/base_units/metric/liter.hpp>
28+
#include <boost/units/base_units/metric/minute.hpp>
29+
#include <boost/units/base_units/si/second.hpp>
30+
#include <boost/type_traits/is_constructible.hpp>
2731

2832
#include <iostream>
2933

@@ -108,3 +112,11 @@ BOOST_AUTO_TEST_CASE(test_dimensionless_conversions) {
108112
BOOST_CONSTEXPR_OR_CONST bu::quantity<bu::divide_typeof_helper<bu::cgs::mass, bu::si::mass>::type> dimensionless_test5(dimensionless_test4);
109113
BOOST_UNITS_CHECK_CLOSE(dimensionless_test5.value(), 2e5);
110114
}
115+
116+
BOOST_AUTO_TEST_CASE(test_unrelated_constructible) {
117+
typedef boost::units::quantity<boost::units::metric::liter_base_unit::unit_type> liter;
118+
typedef boost::units::quantity<boost::units::metric::minute_base_unit::unit_type> minute;
119+
typedef boost::units::quantity<boost::units::si::second_base_unit::unit_type> second;
120+
BOOST_CHECK((!boost::is_constructible<liter, minute>::value));
121+
BOOST_CHECK((boost::is_constructible<second, minute>::value));
122+
}

0 commit comments

Comments
 (0)