
- I had to modify <boost/units/system/si/base.hpp> to include <boost/units/io.hpp>, otherwise the compiler claimed syntax errors for all of the specializations of the unit_info class.
Good point; I'll fix this.
- Compile times even for a relatively small sample were rather large, but this is understandable.
Yeah, compile time is a bear. On the other hand, I haven't gone through the MPL code with a fine-toothed comb yet, so it might be possible to make some improvements there. In any case, for most projects, you would just throw the quantities you want into a precompiled header file, so it should really only be a one-time cost...
- unit_info specializations for the CGS system typedef'd base_type as SI::system, not CGS::system. Is this a bug? This typedef is also omitted in the docs, so I'm not even sure it's necessary.
The quantity conversion code has seen more change than anything else since v0.5.6 - base_type is no longer necessary as I no longer assume that conversions between two unit systems have to be mediated by a base system. Instead, as you can see in <boost/units/systems/si/convert_si_to_cgs.hpp>, you simply provide a template specialization for the base_unit_converter class for each fundamental unit. This marginally increases the typing involved in implementing unit system conversions, but significantly increases the flexibility... I have removed the unnecessary base_type declarations for the next version.
So far my sample program makes two new units, nautical miles and feet. Nautical miles resides in SIext::system, feet resides in imperial::system. It then defines a radar struct that stores a range in nautical miles, and a ceiling in feet, as well as a location in UTM coordinates as meters. There is one function in_range that takes in a UTM coordinate and says whether or not it's in range of the given radar system.
Cool - this sounds like a much more interesting application than most of the largely SI stuff that I use it for...
One issue that using feet brought up was how to correctly specialize the unit_info struct for the unit name string when the name changes in plural form. Could you provide a plural() function that does nothing but forward to name() if it's not over-ridden? e.g.
template <> struct unit_info<imperial::system, length_tag> { typedef imperial::system base_type; static string name() { return "foot"; } static string plural() { return "feet"; } static string symbol() { return "ft"; } };
I guess it would not be a problem in principle to do this. Since the current IO doesn't use the full name anyway, you could just add plural() and have it work. The only downside I can see to adding this to the library (assuming I can figure out how to get an ostream manipulator to enable the choice of full unit names or abbreviations) is that operator<< would have to compare value() against Y(1). Another potential issue is this: What should you call 1 lb. ft.? I'd say one foot pound. How about 2 lb. ft? I'd say two foot pounds. But it could equally reasonably be called two pound feet - it's just a convention. With more involved composite units, these issues become progressively messier, which is one of the reasons why I've tried as much as possible to avoid the morass of IO...
minor nit. Just in implementing this small program I was warned by the compiler of comparing feet to meters multiple times (comparing altitudes). I will try to clean up the code and send it to you if you are interested. I would also be interested if I used your library's facilities correctly.
I'd be very interested to see what you've done with it and to get your overall impression on the documentation and ease of use. Thanks, Matthias ---------------------------------------------------------------- Matthias Schabel, Ph.D. Assistant Professor, Department of Radiology Utah Center for Advanced Imaging Research 729 Arapeen Drive Salt Lake City, UT 84108 801-587-9413 (work) 801-585-3592 (fax) 801-706-5760 (cell) 801-484-0811 (home) matthias dot schabel at hsc dot utah dot edu ----------------------------------------------------------------

Matthias Schabel said: (by the date of Tue, 6 Feb 2007 16:04:15 -0700) Hi, I still haven't looked at it, I should have time for that in few weeks.
In any case, for most projects, you would just throw the quantities you want into a precompiled header file, so it should really only be a one-time cost...
But I wanted to ask if you have some example demonstrating this, or is it explained in docs. Because frankly speaking I don't understand what you mean here. I type 'make clean' and then I type 'make'. Nothing is precompiled at this stage, so how I can save time? My app is huge, and it already takes long to compile, so I prefer to use this "one-time cost" solution. -- Janek Kozicki |

But I wanted to ask if you have some example demonstrating this, or is it explained in docs. Because frankly speaking I don't understand what you mean here. I type 'make clean' and then I type 'make'. Nothing is precompiled at this stage, so how I can save time?
My app is huge, and it already takes long to compile, so I prefer to use this "one-time cost" solution.
Hi Janek, I may have been a bit imprecise previously - there are two issues here : 1) reprocessing of all the header files with every compilation. this overhead can be mitigated by preprocessing those headers that are stable (don't change frequently) such as Boost library headers. the details depend on which compiler you are using; here's a link to the gcc docs: http://gcc.gnu.org/onlinedocs/gcc-4.0.1/gcc/Precompiled-Headers.html 2) doing the compile-time MPL stuff. here, if your program is really only dealing with a restricted set of units, you can use explicit template instantiation : http://www.network-theory.co.uk/docs/gccintro/gccintro_60.html of course, this only works if you are only working with pre-defined units (like from the SI system); if there are numerous unit computations within your main code, this doesn't solve the problem... Matthias ---------------------------------------------------------------- Matthias Schabel, Ph.D. Assistant Professor, Department of Radiology Utah Center for Advanced Imaging Research 729 Arapeen Drive Salt Lake City, UT 84108 801-587-9413 (work) 801-585-3592 (fax) 801-706-5760 (cell) 801-484-0811 (home) matthias dot schabel at hsc dot utah dot edu ----------------------------------------------------------------

AMDG Janek Kozicki <janek_listy <at> wp.pl> writes:
Matthias Schabel said: (by the date of Tue, 6 Feb 2007 16:04:15 -0700)
Hi,
I still haven't looked at it, I should have time for that in few weeks.
In any case, for most projects, you would just throw the quantities you want into a precompiled header file, so it should really only be a one-time cost...
But I wanted to ask if you have some example demonstrating this, or is it explained in docs. Because frankly speaking I don't understand what you mean here. I type 'make clean' and then I type 'make'. Nothing is precompiled at this stage, so how I can save time?
My app is huge, and it already takes long to compile, so I prefer to use this "one-time cost" solution.
The following replacement for dimension speeds up my compilies by about 5x with msvc. struct sort_dims_list_end { enum { size = 0 }; }; template<class T, class Next = sort_dims_list_end> struct sort_dims_list { typedef T item; typedef Next next; enum { size = Next::size + 1 }; }; template<class Sequence, class T> struct replace_front { typedef sort_dims_list< typename static_add<T, typename Sequence::item>::type, typename Sequence::next > type; }; template<class Sequence, class T> struct insert_new { typedef typename boost::mpl::if_<boost::is_same<typename get_tag<typename Sequence::item>::type, static_rational<0> >, typename Sequence::next, Sequence >::type type1; typedef sort_dims_list<T, type1> type; }; template<class Sequence, class T> struct sort_dims_insert { typedef typename boost::mpl::eval_if_c<(Sequence::item::tag_type::value::type::value == T::tag_type::value::type::value), replace_front<Sequence, T>, insert_new<Sequence, T> >::type type; }; template<class T> struct sort_dims_insert<sort_dims_list_end, T> { typedef typename sort_dims_list<T> type; }; template<class Out1, class Out2> struct partition_dims_state { typedef Out1 out1; typedef Out2 out2; }; template<bool> struct partition_dims_state_insert; template<> struct partition_dims_state_insert<true> { template<class State, class T> struct apply { typedef partition_dims_state<sort_dims_list<T, typename State::out1>, typename State::out2> type; }; }; template<> struct partition_dims_state_insert<false> { template<class State, class T> struct apply { typedef partition_dims_state<typename State::out2, sort_dims_list<T, typename State::out1> > type; }; }; template<class Begin, class End, class State, long Value> struct partition_dims_forward_impl { typedef typename Begin::item::tag_type::value::type val; typedef typename partition_dims_forward_impl< typename Begin::next, End, typename partition_dims_state_insert<((val::value) < Value)>::template apply<State, typename Begin::item>::type, Value >::type type; }; template<class End, class State, long Value> struct partition_dims_forward_impl<End, End, State, Value> { typedef State type; }; template<class Sequence, class Output> struct sort_dims_forward; template<int N> struct sort_dims_forward_impl { template<class Begin, class End, class Output> struct apply { typedef typename partition_dims_forward_impl< typename Begin::next, End, partition_dims_state<sort_dims_list_end, sort_dims_list_end>, Begin::item::tag_type::value::type::value >::type partitioned; typedef typename sort_dims_forward<typename partitioned::out1, Output>::type step1; typedef typename sort_dims_insert<step1, typename Begin::item>::type step2; typedef typename sort_dims_forward<typename partitioned::out2, step2>::type type; }; }; template<> struct sort_dims_forward_impl<0> { template<class Begin, class End, class Output> struct apply { typedef Output type; }; }; template<> struct sort_dims_forward_impl<1> { template<class Begin, class End, class Output> struct apply { typedef typename sort_dims_insert<Output, typename Begin::item>::type type; }; }; template<class Sequence, class Output> struct sort_dims_forward { typedef typename sort_dims_forward_impl<Sequence::size>::template apply< Sequence, sort_dims_list_end, Output >::type type; }; template<int N> struct remove_dimensionless { template<class Begin, class Out> struct apply { typedef typename boost::mpl::deref<Begin>::type deref; typedef typename boost::mpl::if_<boost::is_same<typename deref::tag_type, dimensionless_type>, Out, sort_dims_list<deref, Out> >::type type1; typedef typename remove_dimensionless<N - 1>::template apply<typename boost::mpl::next<Begin>::type, type1>::type type; }; }; template<> struct remove_dimensionless<0> { template<class Begin, class Out> struct apply { typedef Out type; }; }; template<class Sequence> struct sort_dims_to_mpl_list { typedef typename boost::mpl::push_front<typename sort_dims_to_mpl_list<typename Sequence::next>::type, typename Sequence::item>::type type; }; template<> struct sort_dims_to_mpl_list<sort_dims_list_end> { typedef mpl::list0<> type; }; /// reduce dimension list to cardinal form /// This algorithm collapses duplicate unit tags, strips resulting dimensionless /// tags, and sorts the resulting list by the tag ordinal value. It guarantees /// that two dimension lists that resolve to the same dimension are represented /// by an identical type template<typename Seq> struct dimension { typedef typename remove_dimensionless< boost::mpl::size<Seq>::value >::template apply<typename boost::mpl::begin<Seq>::type, sort_dims_list_end>::type sequence; typedef typename sort_dims_forward<sequence, sort_dims_list_end>::type type2; typedef typename sort_dims_to_mpl_list<type2>::type type3; typedef typename mpl::if_<mpl::empty<type3>, dimensionless_type, type3>::type type; }; In Christ, Steven Watanabe
participants (3)
-
Janek Kozicki
-
Matthias Schabel
-
Steven Watanabe