
Has anyone extended (even privately) Boost.Units to include support for units of data (bits, bytes, KB, MB, etc)? It seems like this would be a useful addition to Boost.Units. Assuming no, what is the minimum amount of work required to do this myself? There's not a lot of info in the docs on how to define new base units, although I've already begun looking over the source code to try to come up with something.

AMDG Zachary Turner wrote:
Has anyone extended (even privately) Boost.Units to include support for units of data (bits, bytes, KB, MB, etc)? It seems like this would be a useful addition to Boost.Units.
Assuming no, what is the minimum amount of work required to do this myself? There's not a lot of info in the docs on how to define new base units, although I've already begun looking over the source code to try to come up with something
warning untested code. #include <boost/units/base_dimension.hpp> #include <boost/units/base_unit.hpp> #include <boost/units/scale.hpp> #include <boost/units/scaled_base_unit.hpp> // note that the numbers here are arbitrary as long as they are unique. struct data_base_dimension : boost::units::base_dimension<data_base_dimension, 73254> {}; typedef data_base_dimension::dimension_type data_dimension; struct bit_base_unit : boost::units::base_unit<bit_base_unit, data_dimension, 76389> {}; typedef boost::units::scaled_base_unit<bit_base_unit, boost::units::scale<8> > byte_base_unit; namespace boost { namespace units { template<> struct base_unit_info< ::byte_base_unit> { static const char* name() { return("byte"); } static const char* symbol() { return("B"); } }; } } typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<10> > > KB_base_unit; typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<20> > > MB_base_unit; typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<30> > > GB_base_unit; typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<40> > > TB_base_unit; See also http://www.boost.org/doc/html/boost_units/Dimensional_Analysis.html http://www.boost.org/doc/html/boost_units/Units.html I believe that these two pages show creating a minimal SI system from scratch. In Christ, Steven Watanabe

On Wed, Jul 1, 2009 at 7:41 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
AMDG
Zachary Turner wrote:
Has anyone extended (even privately) Boost.Units to include support for units of data (bits, bytes, KB, MB, etc)? It seems like this would be a useful addition to Boost.Units.
Assuming no, what is the minimum amount of work required to do this myself? There's not a lot of info in the docs on how to define new base units, although I've already begun looking over the source code to try to come up with something
warning untested code.
#include <boost/units/base_dimension.hpp> #include <boost/units/base_unit.hpp> #include <boost/units/scale.hpp> #include <boost/units/scaled_base_unit.hpp>
// note that the numbers here are arbitrary as long as they are unique. struct data_base_dimension : boost::units::base_dimension<data_base_dimension, 73254> {}; typedef data_base_dimension::dimension_type data_dimension;
struct bit_base_unit : boost::units::base_unit<bit_base_unit, data_dimension, 76389> {}; typedef boost::units::scaled_base_unit<bit_base_unit, boost::units::scale<8>
byte_base_unit;
namespace boost { namespace units { template<> struct base_unit_info< ::byte_base_unit> { static const char* name() { return("byte"); } static const char* symbol() { return("B"); } }; } }
typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<10> > > KB_base_unit; typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<20> > > MB_base_unit; typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<30> > > GB_base_unit; typedef boost::units::scaled_base_unit<byte_base_unit, boost::units::scale<2, boost::units::static_rational<40> > > TB_base_unit;
See also http://www.boost.org/doc/html/boost_units/Dimensional_Analysis.html http://www.boost.org/doc/html/boost_units/Units.html I believe that these two pages show creating a minimal SI system from scratch.
Thanks for your response. I got this working mostly, but I'm still having difficulty seeing how to tie it all together. I added the following: typedef boost::units::make_system<bit_base_unit>::type data_system; typedef boost::units::unit<data_base_dimension::dimension_type, data_system> capacity; But I'm still not sure how to create and manipulate values with these units. For example, I can do: quantity<capacity> compressed_size; but if I try to assign it to anything I get errors. I tried using the BOOST_UNITS_STATIC_CONSTANT macro to create aliases such as bytes, megabytes, etc but I think this is the wrong approach, is it because all the units above are defined as base units? Ideally I want to be able to type: quantity<capacity> compressed_size = 10000 * bytes; quantity<capacity> total_size = 400000 * bytes; float ratio = compressed_size / total_size; //should be dimensionless quantity<time> duration = 300 * seconds; quantity<data_rate> = total_size / duration; //has dimensions capacity/time

AMDG Zachary Turner wrote:
Thanks for your response. I got this working mostly, but I'm still having difficulty seeing how to tie it all together. I added the following:
typedef boost::units::make_system<bit_base_unit>::type data_system; typedef boost::units::unit<data_base_dimension::dimension_type, data_system> capacity;
But I'm still not sure how to create and manipulate values with these units. For example, I can do:
quantity<capacity> compressed_size;
but if I try to assign it to anything I get errors. I tried using the BOOST_UNITS_STATIC_CONSTANT macro to create aliases such as bytes, megabytes, etc but I think this is the wrong approach, is it because all the units above are defined as base units?
Ideally I want to be able to type:
quantity<capacity> compressed_size = 10000 * bytes;
That won't quite work. Implicit conversions are banned. typedef byte_base_unit::unit_type bytes; quantity<capacity> compressed_size(10000 * bytes()); You can also use BOOST_UNITS_STATIC_CONSTANT(bytes, byte_base_unit::unit_type); to allow 10000 * bytes;
quantity<capacity> total_size = 400000 * bytes;
float ratio = compressed_size / total_size; //should be dimensionless
This ought to work.
quantity<time> duration = 300 * seconds;
quantity<data_rate> = total_size / duration; //has dimensions capacity/tim
This should work if data_rate is defined correctly. In Christ, Steven Watanabe

On Wed, Jul 1, 2009 at 11:26 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
AMDG
Zachary Turner wrote:
Thanks for your response. I got this working mostly, but I'm still having difficulty seeing how to tie it all together. I added the following:
typedef boost::units::make_system<bit_base_unit>::type data_system; typedef boost::units::unit<data_base_dimension::dimension_type, data_system> capacity;
But I'm still not sure how to create and manipulate values with these units. For example, I can do:
quantity<capacity> compressed_size;
but if I try to assign it to anything I get errors. I tried using the BOOST_UNITS_STATIC_CONSTANT macro to create aliases such as bytes, megabytes, etc but I think this is the wrong approach, is it because all the units above are defined as base units?
Ideally I want to be able to type:
quantity<capacity> compressed_size = 10000 * bytes;
That won't quite work. Implicit conversions are banned.
typedef byte_base_unit::unit_type bytes;
quantity<capacity> compressed_size(10000 * bytes());
You can also use BOOST_UNITS_STATIC_CONSTANT(bytes, byte_base_unit::unit_type);
to allow 10000 * bytes;
quantity<capacity> total_size = 400000 * bytes;
float ratio = compressed_size / total_size; //should be dimensionless
This ought to work.
Thanks for your help so far! I know I'm probably just making this too difficult, but it's still not working. I guess I should just post a complete sample so that we can eliminate the snip factor from the list of possible causes (I put them in the boost namespace for the sake of consistency but the same problem arises regardless). //units.hpp #ifndef UNITS_HPP_INCLUDED #define UNITS_HPP_INCLUDED #include <boost/units/base_dimension.hpp> #include <boost/units/base_unit.hpp> #include <boost/units/scale.hpp> #include <boost/units/scaled_base_unit.hpp> #include <boost/units/make_system.hpp> #include <boost/units/static_constant.hpp> #define DECLARE_BASE_UNIT_INFO(base_unit_, name_, symbol_) \ template<> struct base_unit_info<base_unit_> { \ static const char* name() { return name_; } \ static const char* symbol() { return symbol_; } \ }; namespace boost { namespace units { namespace data_capacity { struct data_capacity_base_dimension : base_dimension<data_capacity_base_dimension, 73254> {}; typedef data_capacity_base_dimension::dimension_type data_capacity_dimension; struct bit_base_unit : base_unit<bit_base_unit, data_capacity_dimension, 76389> {}; typedef scaled_base_unit<bit_base_unit, scale<2, static_rational<3> >
byte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<10>
kilobyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<20> megabyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<30> gigabyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<40> terabyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<50> petabyte_base_unit;
} DECLARE_BASE_UNIT_INFO(data_capacity::bit_base_unit, "bit", "b") DECLARE_BASE_UNIT_INFO(data_capacity::byte_base_unit, "byte", "B") DECLARE_BASE_UNIT_INFO(data_capacity::kilobyte_base_unit, "kilobyte", "KB") DECLARE_BASE_UNIT_INFO(data_capacity::megabyte_base_unit, "megabyte", "MB") DECLARE_BASE_UNIT_INFO(data_capacity::gigabyte_base_unit, "gigabyte", "GB") DECLARE_BASE_UNIT_INFO(data_capacity::terabyte_base_unit, "terabyte", "TB") DECLARE_BASE_UNIT_INFO(data_capacity::petabyte_base_unit, "petabyte", "PB") namespace data_capacity { typedef boost::units::make_system<bit_base_unit>::type data_capacity_system; typedef boost::units::unit<data_capacity_base_dimension::dimension_type, data_capacity_system> data_capacity; BOOST_UNITS_STATIC_CONSTANT(bit, bit_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(bits, bit_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(byte, byte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(bytes, byte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(kilobyte, kilobyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(kilobytes, kilobyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(megabyte, megabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(megabytes, megabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(gigabyte, gigabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(gigabytes, gigabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(terabyte, terabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(terabytes, terabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(petabyte, petabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(petabytes, petabyte_base_unit::unit_type); } } } #endif //test.cpp #include "units.hpp" #include <boost/units/quantity.hpp> void foo() { using boost::units::quantity; using namespace boost::units::data_capacity; //Both of these fail with the message that there is no conversion to the destination //type because the construcor is explicit quantity<data_capacity> compressed_size = 1000 * bytes; quantity<data_capacity, int> compressed_size2 = 1000 * bytes; //Succeeds but gives a horribly long warning about conversion from 'double' to 'const int' //at file 'boost/units/detail/conversion_impl.hpp(342)', reference to class template instantiation at //boost/units/quantity.hpp(182) quantity<data_capacity, int> compressed_size3(1000 * bytes); }
quantity<time> duration = 300 * seconds;
quantity<data_rate> = total_size / duration; //has dimensions capacity/tim
This should work if data_rate is defined correctly.
Hopefully once I get this working I'll be able to figure that one out on my own! Thanks Zach

AMDG Zachary Turner wrote:
Thanks for your help so far! I know I'm probably just making this too difficult, but it's still not working. I guess I should just post a complete sample so that we can eliminate the snip factor from the list of possible causes (I put them in the boost namespace for the sake of consistency but the same problem arises regardless).
<snip>
void foo() { using boost::units::quantity; using namespace boost::units::data_capacity;
//Both of these fail with the message that there is no conversion to the destination //type because the construcor is explicit quantity<data_capacity> compressed_size = 1000 * bytes; quantity<data_capacity, int> compressed_size2 = 1000 * bytes;
Implicit conversion between different units is not allowed. Try quantity<data_capacity> compressed_size(1000 * bytes);
//Succeeds but gives a horribly long warning about conversion from 'double' to 'const int' //at file 'boost/units/detail/conversion_impl.hpp(342)', reference to class template instantiation at //boost/units/quantity.hpp(182) quantity<data_capacity, int> compressed_size3(1000 * bytes); }
I'll commit a fix as soon as the regression tests finish locally. In Christ, Steven Watanabe

On Thu, Jul 2, 2009 at 2:07 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
AMDG
Zachary Turner wrote:
Thanks for your help so far! I know I'm probably just making this too difficult, but it's still not working. I guess I should just post a complete sample so that we can eliminate the snip factor from the list of possible causes (I put them in the boost namespace for the sake of consistency but the same problem arises regardless).
<snip> void foo() { using boost::units::quantity; using namespace boost::units::data_capacity;
//Both of these fail with the message that there is no conversion to the destination //type because the construcor is explicit quantity<data_capacity> compressed_size = 1000 * bytes; quantity<data_capacity, int> compressed_size2 = 1000 * bytes;
Implicit conversion between different units is not allowed. Try quantity<data_capacity> compressed_size(1000 * bytes);
Thanks. The confusion came from the fact that the syntax I was trying was being used in some of the examples. But there is something different about those examples, so that's why it wasn't working. One of the trig examples has a line: quantity<plane_angle> theta = 0.375*radians; for example. I suppose it's due to the fact that radians are the "primary" unit for this dimension? That aside, I still think something isn't exactly right. Ultimately I need to be able to print these quantities in different units (for example, if I'm transferring data at 100MB/s I don't want to print this in bits / second). All of these seems to only allow printing of a quantity in its base unit, which here is defined to be bits. I'd like to be able to do something like: quantity<capacity> q = 2180321.0 * bytes; std::cout << q * megabytes << std::endl; or slightly more complicated, quantity<capacity> q = 1.432 * gigabytes; quantity<time> t = 1.5 * hours; std::cout << (q/t) * (megabytes/minute) << std::endl; std::cout << (q/t) * (kilobytes/second) << std::endl; and have it print: 2.07931614 MB for the first example, and 16.2929778 MB / minute 278.066821 KB / second for the second example It seems like this should "just work" since I've defined them all as scaled based units, but instead the first example just prints 1.74426e+007 b MB which means all its doing is formatting it as bits and then appending "MB". Is this possible short of making one system for each type I want to convert between?

AMDG Zachary Turner wrote:
On Thu, Jul 2, 2009 at 2:07 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
AMDG
Zachary Turner wrote:
Thanks for your help so far! I know I'm probably just making this too difficult, but it's still not working. I guess I should just post a complete sample so that we can eliminate the snip factor from the list of possible causes (I put them in the boost namespace for the sake of consistency but the same problem arises regardless).
<snip> void foo() { using boost::units::quantity; using namespace boost::units::data_capacity;
//Both of these fail with the message that there is no conversion to the destination //type because the construcor is explicit quantity<data_capacity> compressed_size = 1000 * bytes; quantity<data_capacity, int> compressed_size2 = 1000 * bytes;
Implicit conversion between different units is not allowed. Try quantity<data_capacity> compressed_size(1000 * bytes);
Thanks. The confusion came from the fact that the syntax I was trying was being used in some of the examples. But there is something different about those examples, so that's why it wasn't working. One of the trig examples has a line:
quantity<plane_angle> theta = 0.375*radians;
for example. I suppose it's due to the fact that radians are the "primary" unit for this dimension?
The difference is that plane_angle is the same unit as radians. In your case, data_capacity is defined as bits, while you are assigning it a value in bytes. Since the units change, the conversion is explicit.
That aside, I still think something isn't exactly right. Ultimately I need to be able to print these quantities in different units (for example, if I'm transferring data at 100MB/s I don't want to print this in bits / second). All of these seems to only allow printing of a quantity in its base unit, which here is defined to be bits. I'd like to be able to do something like:
quantity<capacity> q = 2180321.0 * bytes; std::cout << q * megabytes << std::endl;
The units of q are bits. Thus, the units of the expression that you are printing are bits * megabytes which is printed as "b MB"
It seems like this should "just work" since I've defined them all as scaled based units, but instead the first example just prints
1.74426e+007 b MB
which means all its doing is formatting it as bits and then appending "MB"
In Christ, Steven Watanabe

On Thu, Jul 2, 2009 at 3:41 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
Zachary Turner wrote:
On Thu, Jul 2, 2009 at 2:07 PM, Steven Watanabe<watanabesj@gmail.com> Thanks. The confusion came from the fact that the syntax I was trying was being used in some of the examples. But there is something different about those examples, so that's why it wasn't working. One of the trig examples has a line:
quantity<plane_angle> theta = 0.375*radians;
for example. I suppose it's due to the fact that radians are the "primary" unit for this dimension?
The difference is that plane_angle is the same unit as radians. In your case, data_capacity is defined as bits, while you are assigning it a value in bytes. Since the units change, the conversion is explicit.
Well what then do you think is the "correct" or "best" way to support what I'm trying to do? It seems like a fairly simple use case but at least to me anyway it's turning out to be rather confusing and complicated. For example, quantity<> is defined as template<class Unit> class quantity; yet one of the valid values for Unit is boost::units::dimensionless. So are we specifying a unit or a dimension? Clearly something that is dimensionless is also unitless but it seems inconsistent for values to be either units, or the empty dimension. The examples have many occurences of things such as quantity<si::length>, quantity<si::mass>, quantity<temperature>, all of which in a physical sense are dimensions. feet,yards,meters; kilograms, grams, ounces; fahrenheit, celsius, kelvin are all units. So I would expect to see quantity<fahrenheit>, quantity<ounces>, quantity<inches>, just based on the fact that the template argument is named Unit. However, all of the examples seem to define only 1 valid template argument for quantity per dimension per system. So if you want si mass then there's 1 thing you can pass to quantity<>, even though with all the prefixes there are a multitude of different units for mass that are still based on the si system. I agree that the template argument to quantity should be a unit, but then I would expect to be able to declare a quantity<> parameterized with every possible unit of length measurement, quantity<feet>, quantity<inches>, quantity<mm>, etc. with automatic conversions provided between every combination. Maybe I'm just doing it all wrong, I'm not trying to be a PITA or anything, at this point I really just want it to work :( Maybe units of data storage capacity could be incorporated into boost 1.40 since they're pretty common (especially for programmers), although ultimately it would still be nice if I could understand how to use the library. Thanks for your patience :) Zach

AMDG Zachary Turner wrote:
On Thu, Jul 2, 2009 at 3:41 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
Zachary Turner wrote:
On Thu, Jul 2, 2009 at 2:07 PM, Steven Watanabe<watanabesj@gmail.com> Thanks. The confusion came from the fact that the syntax I was trying was being used in some of the examples. But there is something different about those examples, so that's why it wasn't working. One of the trig examples has a line:
quantity<plane_angle> theta = 0.375*radians;
for example. I suppose it's due to the fact that radians are the "primary" unit for this dimension?
The difference is that plane_angle is the same unit as radians. In your case, data_capacity is defined as bits, while you are assigning it a value in bytes. Since the units change, the conversion is explicit.
Well what then do you think is the "correct" or "best" way to support what I'm trying to do? It seems like a fairly simple use case but at least to me anyway it's turning out to be rather confusing and complicated. For example, quantity<> is defined as
template<class Unit> class quantity;
yet one of the valid values for Unit is boost::units::dimensionless.
I don't think that there is a boost::units::dimensionless. There is a boost::units::si::dimensionless, though.
So are we specifying a unit or a dimension? Clearly something that is dimensionless is also unitless but it seems inconsistent for values to be either units, or the empty dimension.
The examples have many occurences of things such as quantity<si::length>, quantity<si::mass>, quantity<temperature>, all of which in a physical sense are dimensions. feet,yards,meters; kilograms, grams, ounces; fahrenheit, celsius, kelvin are all units. So I would expect to see quantity<fahrenheit>, quantity<ounces>, quantity<inches>, just based on the fact that the template argument is named Unit.
In general you should read boost::units::si::length as the unit of length in the si system.
However, all of the examples seem to define only 1 valid template argument for quantity per dimension per system. So if you want si mass then there's 1 thing you can pass to quantity<>, even though with all the prefixes there are a multitude of different units for mass that are still based on the si system.
The official SI unit of mass is kilograms. The si system represents a unique set of units.
I agree that the template argument to quantity should be a unit, but then I would expect to be able to declare a quantity<> parameterized with every possible unit of length measurement, quantity<feet>, quantity<inches>, quantity<mm>, etc. with automatic conversions provided between every combination.
The conversions are provided. They are not implicit.
Maybe I'm just doing it all wrong, I'm not trying to be a PITA or anything, at this point I really just want it to work :(
Maybe units of data storage capacity could be incorporated into boost 1.40 since they're pretty common (especially for programmers), although ultimately it would still be nice if I could understand how to use the library.
In Christ, Steven Watanabe

Just to be concrete, I've reworked your code a bit to eliminate extraneous complexity : #include <iostream> #include <boost/units/base_dimension.hpp> #include <boost/units/base_unit.hpp> #include <boost/units/io.hpp> #include <boost/units/scale.hpp> #include <boost/units/scaled_base_unit.hpp> #include <boost/units/make_system.hpp> #include <boost/units/static_constant.hpp> #include <boost/units/quantity.hpp> #define DECLARE_BASE_UNIT_INFO(base_unit_, name_, symbol_) \ template<> struct base_unit_info<base_unit_> { \ static const char* name() { return name_; } \ static const char* symbol() { return symbol_; } \ }; namespace boost { namespace units { struct data_capacity_base_dimension : base_dimension<data_capacity_base_dimension, 73254> {}; typedef data_capacity_base_dimension::dimension_type data_capacity_dimension; struct bit_base_unit : base_unit<bit_base_unit,data_capacity_dimension, 76389> {}; typedef scaled_base_unit<bit_base_unit, scale<2, static_rational<3> >
byte_base_unit;
typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<10>
kilobyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<20> megabyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<30> gigabyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<40> terabyte_base_unit; typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<50> petabyte_base_unit;
DECLARE_BASE_UNIT_INFO(bit_base_unit, "bit", "b") DECLARE_BASE_UNIT_INFO(byte_base_unit, "byte", "B") DECLARE_BASE_UNIT_INFO(kilobyte_base_unit, "kilobyte", "KB") DECLARE_BASE_UNIT_INFO(megabyte_base_unit, "megabyte", "MB") DECLARE_BASE_UNIT_INFO(gigabyte_base_unit, "gigabyte", "GB") DECLARE_BASE_UNIT_INFO(terabyte_base_unit, "terabyte", "TB") DECLARE_BASE_UNIT_INFO(petabyte_base_unit, "petabyte", "PB") BOOST_UNITS_STATIC_CONSTANT(bit, bit_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(bits, bit_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(byte, byte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(bytes, byte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(kilobyte, kilobyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(kilobytes, kilobyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(megabyte, megabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(megabytes, megabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(gigabyte, gigabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(gigabytes, gigabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(terabyte, terabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(terabytes, terabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(petabyte, petabyte_base_unit::unit_type); BOOST_UNITS_STATIC_CONSTANT(petabytes, petabyte_base_unit::unit_type); } } using namespace boost::units; template<class U,class Y> void outputDataCapacity(const quantity<U,Y>& q) { static const Y bits_per_byte = 8, bits_per_kilobyte = 8*1024, bits_per_megabyte = 8*1024*1024, bits_per_gigabyte = 8*1024*1024*1024; const quantity<bit_base_unit::unit_type,Y> qb(q); const Y qv(qb.value()); if (qb.value() <= bits_per_byte) std::cout << qb << std::endl; else if (qb.value() <= bits_per_kilobyte) std::cout << quantity<byte_base_unit::unit_type,Y>(q) << std::endl; else if (qb.value() <= bits_per_megabyte) std::cout << quantity<kilobyte_base_unit::unit_type,Y>(q) << std::endl; else if (qb.value() <= bits_per_gigabyte) std::cout << quantity<megabyte_base_unit::unit_type,Y>(q) << std::endl; else std::cout << "error..." << std::endl; return; } int main() { quantity<bit_base_unit::unit_type, int> c1(1000 * bits); quantity<byte_base_unit::unit_type, int> c2(1000 * bytes); quantity<kilobyte_base_unit::unit_type, int> c3(1000 * kilobytes); quantity<megabyte_base_unit::unit_type, int> c4(1000 * megabytes); quantity<bit_base_unit::unit_type, int> d1(1 * gigabyte); quantity<byte_base_unit::unit_type, int> d2(1 * gigabyte); quantity<kilobyte_base_unit::unit_type, int> d3(1 * gigabyte); quantity<megabyte_base_unit::unit_type, int> d4(1 * gigabyte); std::cout << c1 << std::endl; std::cout << c2 << std::endl; std::cout << c3 << std::endl; std::cout << c4 << std::endl; std::cout << std::endl; std::cout << d1 << std::endl; std::cout << d2 << std::endl; std::cout << d3 << std::endl; std::cout << d4 << std::endl; std::cout << std::endl; for (double v=1.0;v<=std::pow(2.0,24);v*=2.0) { outputDataCapacity(v*bits); } return 0; } This code compiles and runs correctly and does what you would expect, outputting : 1000 b 1000 B 1000 KB 1000 MB 2147483647 b 1073741824 B 1048576 KB 1024 MB 1 b 2 b 4 b 8 b 2 B 4 B 8 B 16 B 32 B 64 B 128 B 256 B 512 B 1024 B 2 KB 4 KB 8 KB 16 KB 32 KB 64 KB 128 KB 256 KB 512 KB 1024 KB error... The conceptual problem that you're having is wanting the program to somehow "know" that you want a quantity that is represented in bits to be output as megabytes. However, while the program knows that those units are convertible, there is no way for it to know that you want megabytes instead of gigabytes, kilobytes, or any other unit for which the conversion is defined. Thus, if you want specific output formatting, you need to do it yourself like I've done in outputDataCapacity... Hope this helps. Matthias

void foo() { using boost::units::quantity; using namespace boost::units::data_capacity;
//Both of these fail with the message that there is no conversion to the destination //type because the construcor is explicit quantity<data_capacity> compressed_size = 1000 * bytes; quantity<data_capacity, int> compressed_size2 = 1000 * bytes;
Implicit conversion is not allowed, and default value type is double - try : quantity<data_capacity> compressed_size(1000.0*bytes); quantity<data_capacity,int> compressed_size2(1000*bytes);
//Succeeds but gives a horribly long warning about conversion from 'double' to 'const int' //at file 'boost/units/detail/conversion_impl.hpp(342)', reference to class template instantiation at //boost/units/quantity.hpp(182) quantity<data_capacity, int> compressed_size3(1000 * bytes); }
If I remember correctly, this stems from the use of double precision in the conversion code. I think it would be difficult to get rid of this - most computations involving unit conversions do not involve exact integer arithmetic... Matthias

AMDG Matthias Schabel wrote:
//Succeeds but gives a horribly long warning about conversion from 'double' to 'const int' //at file 'boost/units/detail/conversion_impl.hpp(342)', reference to class template instantiation at //boost/units/quantity.hpp(182) quantity<data_capacity, int> compressed_size3(1000 * bytes); }
If I remember correctly, this stems from the use of double precision in the conversion code. I think it would be difficult to get rid of this - most computations involving unit conversions do not involve exact integer arithmetic...
Getting rid of the warning shouldn't be a problem. I'm just going to add a cast. This ought to be safe, since the conversion is explicit. A cast is only needed at the end, because all the conversion code is careful to deduce the correct return type for all operators. In Christ, Steven Watanabe
participants (3)
-
Matthias Schabel
-
Steven Watanabe
-
Zachary Turner