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
"unity"
(probably defined in some future <unity> header) UDLs, respecting the
position
where "multiples" and "unities" appears.
Allowing "most vexing phrase" and any classes as parameters to UDL, it
might be
possible.
1 - Composite UDL ( The blue code is new syntax )
Consider:
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
quantity<...>
// 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 ->
speed;
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
seconds
// 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
itself
// "m" is a postfix operator in "newton" to
"newton-meter"
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.
BR
Cleiton
<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
"unity"
(probably defined in some future <unity> header) UDLs, respecting the
position
where "multiples" and "unities" appears.
Allowing "most vexing phrase" and any classes as parameters to UDL, it
might be
possible.
1 - Composite UDL ( The blue code is new syntax )
Consider:
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
quantity<...>
// 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 ->
speed;
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
seconds
// 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
itself
// "m" is a postfix operator in "newton" to
"newton-meter"
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.
BR
Cleiton
Received on 2020-06-03 20:58:59