Physical Boost.Units User Defined Literals
Asked Answered
B

2

7

Now that we soon have user defined literals (UDL), in GCC 4.7 for example, I'm eagerly waiting for (physical) unit libraries (such as Boost.Units) using them to ease expression of literals such as 1+3i, 3m, 3meter or 13_meter. Has anybody written an extension to Boost.Units using UDL supporting this behaviour?

Breakaway answered 13/2, 2012 at 9:3 Comment(2)
Considering that the only compiler with UDL support is GCC, and even then only in an unstable release, I'm guessing no. Also, UDLs that don't start with an _ are reserved for future standards; you can't write them yourself.Did
That is good to know! I just wondered how UDL might conflict with current numeric literal suffixes l, f and d. The _ requirement answers that question.Phallic
B
5

No one has come out with such an extension. Only gcc (and possibly IBM?) has UDL so it might be a while. I'm hoping some kind of units makes it into tr2 which is starting about now. If that happens I'm sure UDL for units will come up.

This works:

//  ./bin/bin/g++ -std=c++0x -o units4 units4.cpp

#include <boost/units/unit.hpp>
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si.hpp>

using namespace boost::units;
using namespace boost::units::si;

quantity<length, long double>
operator"" _m(long double x)
{ return x * meters; }

quantity<si::time, long double>
operator"" _s(long double x)
{ return x * seconds; }

int
main()
{
  auto l = 66.6_m;
  auto v = 2.5_m / 6.6_s;
  std::cout << "l = " << l << std::endl;
  std::cout << "v = " << v << std::endl;
}

I think it wouldn't be too hard to go through you favorite units and do this.

Concerning putting these in a library: The literal operators are namespace scope functions. The competition for suffixes is going to get ugly. I would (if I were boost) have

namespace literals
{
...
}

Then Boost users can do

using boost::units::literals;

along with all the other using decls you typically use. Then you won't get clobbered by std::tr2::units for example. Similarly if you roll your own.

Betts answered 14/2, 2012 at 1:40 Comment(6)
Annoyance #1: Literal operators can only take a few argument types. It would be nice to have versions that return float and double as well as long double so calculations aren't promoted up to long double all the time? ADL won't pick by return type only - precision specific namespaces and using? Ugh.Betts
Annoyance #2: in addition to all the units, it would be nice to have at least common multiples. e.g. not just "m" but "km", "cm", "mm" for lengths, "Hz", "kHz", "MHz", "GHz" for frequency. It could get tedious - or involve some macros.Betts
There are some applications where size is a constraint. Matrix math can fall into this category. OTOH, it wouldn't be difficult to either cast a literal to your preferred size or have different suffixes for different return types - f_km for float kilometers. Finally, literals tend to not dominate code - they are generally few. As long as an operation on some large object like a matrix wouldn't promote intermediate variables to an unmanageable size then it's OK. I guess these annoyances are not that big a deal.Betts
I admit there are some (many) situations where promoting to a higher precision is at least OK and possibly beneficial.Betts
I have implemented a simple set of user defined literals for boost units for the S.I. units including all S.I. prefixes here.Calculous
@AndrewCecil, nice, have you think in a way of dealing with combined units expressions, (such as 1 m/s, 1 meter per second)? See my answer.Northeasterly
N
3

In my opinion there is not much gain in using literals for Boost.Units, because a more powerful syntax can still be achieved with existing capabilities.

In simple cases, looks like literals is the way to go, but soon you see that it is not very powerful. For example, you still have to define literals for combined units, for example, how do you express 1 m/s (one meter per second)?

Currently:

auto v = 1*si::meter/si::second; // yes, it is long

but with literals?

// fake code
using namespace boost::units::literals;
auto v = 1._m_over_s; // or 1._m/si::second; or 1._m/1_s // even worst

A better solution can be achieved with existing features. And this is what I do:

namespace boost{namespace units{namespace si{ //excuse me!
namespace abbreviations{
    static const length             m   = si::meter;
    static const time               s   = si::second;

    // ...
}
}}} // thank you!

using namespace si::abbreviations;
auto v = 1.*m/s;

In the same way you can do: auto a = 1.*m/pow<2>(s); or extend the abbreviations more if you want (e.g. static const area m2 = pow<2>(si::meter);)

What else beyond this do you want?

Maybe a combined solution could be the way

auto v = 1._m/s; // _m is literal, /s is from si::abbreviation combined with operator/

but there will be so much redundant code and the gain is minimal (replace * by _ after the number.)

One drawback of my solution is that it polutes the namespace with common one letter names. But I don't see a way around that except to add an underscore (to the beginning or the end of the abbreviation), as in 1.*m_/s_ but at least I can build real units expressions.

Northeasterly answered 17/12, 2013 at 22:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.