Как автоматически добавлять литеральные определения, основанные на одном определяемом пользователем литерале?

C++11 предложения пользовательские литералы. Я только начал играть с ними, что заставило меня задуматься, можно ли будет автоматически добавить все СИ множители к одному литералу я определяю?

Например, если я определю

Length operator "" _m(long double m) {
return Length(m); // Length in meters
}

где Length это подкласс некоторых Units базовый класс, я хотел бы иметь механизм для автоматически добавить (в том же духе, что и повысить операторы) Множители СИ для всех литералов, которые возвращают Length:

// these are added automatically when defining the literal "_m":
// Length in:
Length operator "" _Ym(long double Ym);  // Yottameters
Length operator "" _Zm(long double Zm);  // Zetameters
...                                      // ...
...                                      // ...
Length operator "" _km(long double km);  // kilometers
Length operator "" _mm(long double mm);  // millimeters
...                                      // ...
...                                      // ...
Length operator "" _zm(long double zm);  // zeptometers
Length operator "" _ym(long double ym);  // yoctometers

Насколько я мог видеть, кроме, возможно, некоторой макро-магии, нет способа сделать это автоматически, так как все пользовательские литералы нуждаются в явный определение.

..или я что то пропускаю?

11

Решение

Я не думаю, что есть способ сделать именно то, что вы просите, без «странных макросов». Это насколько я мог получить:

template<typename T, T (*op)(long double)>
struct SI
{
// ...
constexpr static T micro = op (.000001);
constexpr static T milli = op (.001);
constexpr static T kilo = op (1000);
constexpr static T mega = op (1000000);
// ...
};

struct Length
{
constexpr Length(long double d) : _d(d) { }
constexpr operator long double() { return _d; }
long double _d;
};

constexpr Length operator "" _m(long double m) {
return Length(m);
}

typedef SI<Length, ::operator "" _m> SI_Length;

int main()
{
constexpr Length l = 3 * SI_Length::kilo;
static_assert(l == 3000, "error");
}

Если разрешены причудливые макросы, то что-то вроде следующего должно сделать эту работу:

#define DEFINE_SI_MULTIPLIERS(T, unit) \
constexpr T operator "" _u ## unit(long double m) \
{ return ::operator "" _ ## unit(0.000001 * m); } \
constexpr T operator "" _m ## unit(long double m) \
{ return ::operator "" _ ## unit(0.001 * m); } \
constexpr T operator "" _k ## unit(long double m) \
{ return ::operator "" _ ## unit(1000 * m); } \
// ...

DEFINE_SI_MULTIPLIERS(Length, m)

int main()
{
constexpr Length l = 3.0_km;
static_assert(l == 3000, "error");
}
3

Другие решения

Вы не можете использовать operator "" _m(const char *) аромат, пока вы готовы разбирать поплавки самостоятельно? Это позволяет писать 1234k_m вызывая общий анализатор с поддержкой SI для ваших значений с плавающей запятой.

-1

По вопросам рекламы [email protected]