Boost logo

Boost Users :

Subject: Re: [Boost-users] [Units] implicit conversion of quantities
From: Christopher Bruns (cmbruns_at_[hidden])
Date: 2009-03-05 18:37:17


Steven Watanabe wrote:
> In this particular case, I would suggest writing the function as a template
> and casting.  In general you can write a forwarding overload that casts as
> appropriate.

Thanks Steven for the advice. I consulted Matthias Schabel off list
to help figure out how to get this working. In case others have
similar needs, I am attaching my modified test program.

/* =================================== */
#include <boost/units/systems/si.hpp>
#include <boost/units/base_units/metric/angstrom.hpp>
#include <iostream>

namespace boost { namespace units
{
   typedef metric::angstrom_base_unit::unit_type angstrom_unit;
   BOOST_UNITS_STATIC_CONSTANT(angstrom, angstrom_unit);

   typedef scaled_base_unit<
           si::meter_base_unit,
           scale<10, static_rational<-9> > > nanometer_base_unit;

   typedef nanometer_base_unit::unit_type nanometer_unit;
   BOOST_UNITS_STATIC_CONSTANT(nanometer, nanometer_unit);

} } // namespace boost::units

using namespace boost::units;
using namespace std;

// First version of showBondLength takes a specific quantity type (nanometers)
std::ostream& showBondLength(quantity<nanometer_unit> len, std::ostream& os) {
    // This implementation could be compiled into a library.
    os << len << std::endl;
}

// Second version of showBondLength can take any length type, and casts it to
// the specific type. The parameter type is a bit long winded for a public API
// method, but not unreadable.
template<class Y>
std::ostream& showBondLength(quantity<unit<length_dimension, Y> > len,
std::ostream& os) {
    // This (simple, forwarding) implementation must be fully defined
in a header.
    return showBondLength( (quantity<nanometer_unit>)len, os);
}

int main()
{
    // These constructors all work; conversions are automatic
    quantity<nanometer_unit> len1(0.152 * nanometer);
    quantity<angstrom_unit> len2(1.52 * angstrom);
    quantity<nanometer_unit> len3(1.52 * angstrom);
    quantity<angstrom_unit> len4(0.152 * nanometer);

    // These three calls are OK, nanometer quantity is passed
    showBondLength(0.152 * nanometer, cout);
    showBondLength(len1, cout);
    showBondLength(len3, cout);

    // Explicit casts to nanometer are OK for angstrom quantities...
    // but yuck
    showBondLength( (quantity<nanometer_unit>)(1.52 * angstrom), cout );
    showBondLength( (quantity<nanometer_unit>)len2, cout );
    showBondLength( (quantity<nanometer_unit>)len4, cout );

    // These all (used to) fail to compile before templated version was added.
    // Users want implicit conversion here from angstroms to nanometers
    showBondLength(1.52 * angstrom, cout);
    showBondLength(len1, cout);
    showBondLength(len2, cout);
    showBondLength(len3, cout);
    showBondLength(len4, cout);

    // Conversion from meters works too
    showBondLength(3.0 * si::meters, std::cout);

    // Non-length quantities correctly fail to compile
    // showBondLength(3.0 * si::seconds, std::cout);

    return 0;
}
/* =================================== */


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net