Как определить, какой параметр шаблона перечисления использовался, фактически не сохраняя это перечисление в одном из атрибутов класса?

#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 выражениями функциями.