
Since the library does not allow for mixed storage of quantities e.g. in vectors, further workarounds will be necessary when dealing linear algebra like BLAS, LAPACK or other advanced numerical libraries.
Perhaps Boost.Any provides a solution to this issue? This code compiles OK :
BLAS does not congest boost::anys. It crunches numbers. Bare-bone floating point numbers, in single precision and contiguous memory for best performance. I like the picture of a conveyor belt for the transportation of my quantities: Near the end of the belt, there is a last check that everything is in correct shape (aka unit) and then - off it goes: Undressed of all other attributes, the naked numbers get fed into that horrible numbercrunching monster machinery. After getting out on the other side, they will get nicely dressed again and released into the shiny world anew. :-) Consequently, I consider a separation of concerns here: To the number crunching monster, it should look like a POD floating point field. To the outside, we need to dress these numbers with their further attributes. That could be done by some proxy or facade object that models a quantity but only holds a reference to the actual location of the numerical value instead of the numerical value itself. Those proxy objects could be both either static or dynamic in nature, just as needed. A separate object for each number, that would clearly incur a noticeable overhead. To keep that manageable, it appears quite practicable to provide one such object for larger parts of the floating point field, implementing the usual sequence semantics. (More gentle minds do not feed those cute quantities to a monster, they do perform a conversion into a dimensionless system beforehand.)
Clearly, there is a limit to what one can accomplish when converting between a data stream of raw bytes to a class.
I would have expected an attempt to catch at least the major sources of errors. Otherwise you end up with the same kind of vulnerability as the Mars Climate Orbiter teams. This time, not on the level of subroutine calls but of files written by on program and read by the another one. For an example, you could check whether the stringified unit of the quantity that is to be deserialized is the same as the stringified unit of the quantatity that has previously serialized. I.e. something along the lines of template<class Archive,class Unit,class Y> inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int version) { static std::string s1=stringify(unit<Dim,System>()); std::string s2(1); ar & q.value(); ar & s2; if (s1!=s2) throw incompatibilty_exception(q, s); }
Furthermore, the overhead involved in storing specific type information on units and quantities could be significant, so that storing a large array of quantities would occupy dramatically more disk space than the corresponding array of value types.
Cleary, safety does not come for free. However in the case of a large vector of quantities of the same type (the only one you considered so far), the unit need to get checked only once for the whole vector, not repeatedly for each and every element therein (much like the sequence semantics I mentioned above). That should alleviate the associated overhead sufficiently to get manageable again. Yours, Martin.