C++ Logo


Advanced search

Physical Units / Composite UDL / Named postfix

From: Cleiton Santoia <cleitonsantoia_at_[hidden]>
Date: Wed, 3 Jun 2020 22:55:39 -0300
    I was looking at p1935r2.html
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1935r2.html> and
decided to give my 2 cents : "composite" UDLs.

    One of the dreams of every "Units" library is to be able define
k,c,m... "multiple"
UDLs ( defined probably in <ratio> ) and combine them with A, m and L
(probably defined in some future <unity> header) UDLs, respecting the
where "multiples" and "unities" appears.

   Allowing "most vexing phrase" and any classes as parameters to UDL, it
might be

1 - Composite UDL ( The blue code is new syntax )


template<typename T, typename Ratio_T>
struct quantity : Ratio_T {
    T quant;
    constexpr quantity (T v) : quant(v) {}

constexpr quantity<long double, std::kilo> operator"" k ( long double v )
    return {v};

struct unity {};

template<typename T, typename Ratio_T>
struct len : quantity<T, Ratio_T>, unity {
   using quantity<T, Ratio_T>::quantity;

auto pi_km = 3.1415k; // 3.1415 kilos without unity works fine in c++17

template<typename T, typename Ratio_T>
constexpr length<T, Ratio_T> operator"" m ( const quantity<T, Ratio_T>& q )
    return {q};

auto l = 3.1415km; // 3.1415 kilometers
                   // since udl "km" cannot be found, try 3.1415k
                   // if it exists, (it does) evaluates to quantity<...>
                   // now, try to find UDL "m" that works with
                   // if it exists, (it does) evaluates to len<...>.

Ok I´m aware that 'most vexing' + 'overload on classes' might become a
parsing nightmare.

2 - Another possible design is "postfix named operator" ( could work even
on runtime )
Consider previous class quantity, plus a postfix member "A" for amperes

template<typename T, typename Ratio_T>
struct quantity : Ratio_T {
    T quant;
    constexpr quantity (T v) : quant(v) {}

    // postfix syntax, like postfix ++
    constexpr length<T, Ratio_T> operator A(int) {
        return {quant};

auto x = 10.0kA; // x = 10 kilo Ampers, ( most vexing finds 10.0m, then
finds postfix "A" in quantity<...>
auto y = 11.0k; // y = 11 kilo ( just quantity<...> ), without any unity
auto z = y A; // z = 11 kilo Ampers, ( need a space between y and A );

3 - Ambiguity ( Little case of "m" that may be milli or meter )

template<typename T>
struct ambiguous_m {
    T quant;
constexpr ambiguous_m<long double> operator"" m ( long double v )
    return {v};

template<typename T>
constexpr length<T, std::mili> operator"" m ( const ambiguous_m<T>& v )
    return {v};

const auto s = 1s; // chrono 1 second;

template<typename T, typename Rep, typename Period>
constexpr speed< length<T, std::mili>, std::chrono::duration<Rep, Period> >
  operator /( const ambiguous_m<T>& x, std::chrono::duration<Rep, Period>
dur ) {
  return {x, dur};

auto x = 10.0mm; // ok ambiguous_m sufixxed by another m -> millimeter;
auto z = 20.0m/s; // ok ambiguous_m "divided" by chrono::duration ->

or define m as meter since the beginning, instead of ambiguous_m, I´m open
to opinions.

4 - Unicode identifiers

auto x = 10.0µA; // micro Ampere
auto y = 1.7rad/s²; // rad is an UDL that converts 1.7 in radian type
                     // "s²" might be a constant of type square seconds
                     // "/" is an overloaded operator on radians and square
                     // y is of type "angular acceleration"

auto z = 3m³; // "m³" is a udl: constexpr meter operator""
m³(unsigned long long int) ...

auto e = 12.0N·m; // "N" is an UDL that converts 12.0 in "struct newton"
                     // "·" is a postfix operator in "newton" to newton
                     // "m" is a postfix operator in "newton" to

I still have some concerns upon the praticallity, and how this whould be
typed in keyboards around the world, in my keyboard I do have easy ¹ ² ³
and °, but not ·, nor µ.
Nontheless, 10.0µA is a beautiful code.


Received on 2020-06-03 20:58:59