#c #c 11
#c #c 11 #c #c 11
Вопрос:
Это не первый раз, когда я попадаю в это. На этот раз я играл с классом «двоичный угол» (целое число без знака отображается в круг 0-360 градусов или 0-180 градусов). Разные объекты находятся в разных диапазонах. Иногда оно равно 0-360, а углы некоторых объектов равны -180 — 180 . Я хочу, чтобы это делалось автоматически, когда объект преобразуется к «арифметическим» значениям в градусах или радианах. Я сохраняю тип «span» как атрибут enum класса, и это работает, но я думаю, что это неправильно. Должен быть способ статически протестировать этот параметр шаблона.
Я знаю, как использовать статические проверки, такие как «is_arithmetic», «is_unsigned» и т.д. Но я не могу найти то, что я ищу.
объявление перечисления:
enum cycle {
FULL, ///< 0 to 360deg
HALF, ///< 0 to 180deg
FULL_SYMMETRIC, ///< -180deg to 180deg
HALF_SYMMETRIC ///< -90deg to 90deg
};
объявление класса:
/// Binary angle representation with conversion to/from DEG and RAD
template<typename U = uint32_t, enum cycle c = FULL>
class angle {
U bin_angle;
static const enum cycle type = c;
public:
и функция-член извлечения градуса / радиана
/// Get current value in degrees or, optionally, in radians represented
/// by the floating point type D
template<typename D>
D get(enum angle_units au = DEG) const {
static_assert(std::is_arithmetic<D>::value,
"The angle can only be requested as an arithmetic type");
D circle_ang = cycle_span<D>(type);
D ang = D(0);
if (bin_angle != U(0)) {
// XXX there must be a better way than to use long double
long double ratio =
(long double) (maxU()) / (long double) (bin_angle);
ang = (circle_ang) / D(ratio);
}
if (ang > cycle_end<D>(type)) {
ang -= circle_ang;
}
if (au == RAD) {
ang = deg2rad<D>(ang);
}
return ang;
}
есть ли способ лучше?
Комментарии:
1. Вы бы упростили свою проблему, введя
angle
класс и подумав о том, как с этим справиться.2. Зачем вам хранить перечисление в элементе?
c
является параметром шаблона шаблона класса, которыйget()
является членом. Вы можете просто использоватьc
вместоtype
!?3. @Michael Kenzel Спасибо! Иногда это так очевидно и так просто … вы даже не потрудились попробовать это. … это работает!
Ответ №1:
Майкл Кензел прав — это был один из тех моментов «Dah». Код был изменен на
// Binary angle representation with conversion to/from DEG and RAD
template<typename U = uint32_t, enum cycle span = FULL>
class angle {
U bin_angle;
public:
и
/// Get current value in degrees or, optionally, in radians represented
/// by the floating point type D
template<typename D>
D get(enum angle_units au = DEG) const {
static_assert(std::is_arithmetic<D>::value,
"The angle can only be requested as an arithmetic type");
D circle_ang = cycle_span<D>(span);
D ang = D(0);
if (bin_angle != U(0)) {
// XXX there must be a better way than to use long double
long double ratio =
(long double) (maxU<U>()) / (long double) (bin_angle);
ang = (circle_ang) / D(ratio);
}
if (ang > cycle_end<D>(span)) {
ang -= circle_ang;
}
if (au == RAD) {
ang = deg2rad<D>(ang);
}
return ang;
}
и это работает точно так же, как и раньше. Мне даже не приходило в голову, что параметр шаблона может использоваться как атрибут или переменная.
Комментарии:
1. вы также можете использовать его как параметр объявления или
usingtypedef
дляintegral_constant
, если вам нужно иметь доступ к используемомуenum
значению извне. Обратите внимание, что i работает во время компиляции, поэтому вы можете использовать его сconstexpr
выражениями функциями.