Тип данных C с пользовательским диапазоном [0, 64]?

#c #struct #custom-data-type

#c #struct #пользовательский тип данных

Вопрос:

Я искал похожие вопросы, но не нашел своего ответа.

В принципе, мне нужно объявить / определить переменную, которая имеет определенный диапазон от 0 до 64 включительно. Должен ли я использовать перечисление? Структура? Могу ли я сделать это при объявлении переменной? Я хочу использовать его в структуре.

Конечно, я мог бы написать несколько проверок if / else, но должен быть более простой способ без создания массива [64].

Комментарии:

1. Включен 64 или нет? Если нет, вы можете использовать битовое поле.

2. Существуют целочисленные типы с фиксированной шириной.

3. Включены как 0, так и 64. Если это поможет, предполагается, что он представляет стеки инвентаря в Minecraft. Максимальный размер стека равен 64. 0 пуст.

4. Это зависит от того, как вы хотите его использовать и почему вы этого хотите? Например, это для экономии места или для обнаружения ошибок вне диапазона?

Ответ №1:

Если вам нужно только ограниченное целое число, вы можете просто проверить диапазон в конструкторе. Вот так:

 #include <stdexcept>

template<int max>
class ConstrInt {
public:
   ConstrInt(int val) {
      if (val > max)
         throw std::out_of_range("");
      m_val = val; 
   }

   int value() const {
      return m_val;
   }
private:
   int m_val;
};



int main(){
   ConstrInt<64> a{1};
   auto aa = a.value();
   ConstrInt<64> b{65};  // exception for > 64
}
 

Комментарии:

1. На самом деле я надеялся, что смогу использовать символ (меньшего размера) и ограничить его значением [0, 64].

2. Не могу ли я определить перечисление с диапазоном от 0 до 64 включительно, не вводя вручную каждое значение?

3. @Kampfkeksgeschwader: Перечисления имеют минимальный диапазон, который уже округлен до чуть ниже следующей степени двойки (т.Е. 127), и вы также пропускаете арифметические операции целочисленного типа.

Ответ №2:

Должен ли я использовать перечисление?

Я не понимаю, как это было бы полезно.

Структура?

Если вы хотите определить пользовательский тип данных, тогда вам нужно определить класс (структуры — это классы).

Могу ли я сделать это при объявлении переменной?

Вы можете определить переменные пользовательских типов данных, если это то, что вы имеете в виду.

Конечно, я мог бы написать несколько проверок if / else, но должен быть более простой способ без создания массива [64].

Нет необходимости создавать массив только для проверки, находится ли значение в пределах диапазона. Вот пример проверки:

 if (x >= 0 amp;amp; x <= 64)
 

Ответ №3:

Вы могли бы определить класс, содержащий an unsigned char , и заставить его обтекать точно так же, как это делают встроенные целочисленные типы без знака, так что 0 - 1 это приводит к 64 и это 64 1 приводит к 0 .

Пример:

 template<unsigned End = 64>
class usmall {
public:
    // implicit conversion constructor, making sure the value is in the range [0, End]
    usmall(unsigned char v = 0) : data(v % (End   1)) {}

    // implicit user defined conversion operator
    operator unsigned char () const { return data; }

    // pre increment and decrement operators
    usmallamp; operator  () { if(data==End) data = 0; else   data; return *this; }
    usmallamp; operator--() { if(data==0) data = End; else --data; return *this; }

    // post increment and decrement operators
    usmall operator  (int) { usmall rv(*this);   *this; return rv; }
    usmall operator--(int) { usmall rv(*this); --*this; return rv; }

    // common arithmetic operators
    usmallamp; operator =(const usmallamp; rhs) {
        data = (data   rhs.data) % (End   1);
        return *this;
    }
    
    usmallamp; operator-=(const usmallamp; rhs) {
        if(data < rhs.data) data  = (End   1);
        data -= rhs.data;
        return *this;
    }

    usmallamp; operator*=(const usmallamp; rhs) {
        data = (data * rhs.data) % (End   1);
        return *this;
    }
    
    usmallamp; operator/=(const usmallamp; rhs) {
        data /= rhs.data;
        return *this;
    }

private:
    unsigned char data;
};

// free arithmetic functions
template<unsigned End>
auto operator (const usmall<End>amp; lhs, const usmall<End>amp; rhs) {
    usmall rv(lhs);
    rv  = rhs;
    return rv;
}

template<unsigned End>
auto operator-(const usmall<End>amp; lhs, const usmall<End>amp; rhs) {
    usmall rv(lhs);
    rv -= rhs;
    return rv;
}

template<unsigned End>
auto operator*(const usmall<End>amp; lhs, const usmall<End>amp; rhs) {
    usmall rv(lhs);
    rv *= rhs;
    return rv;
}

template<unsigned End>
auto operator/(const usmall<End>amp; lhs, const usmall<End>amp; rhs) {
    usmall rv(lhs);
    rv /= rhs;
    return rv;
}
 

Пример:

 #include <iostream>

int main() {
    usmall foo = 3;
    usmall bar = 30;
    usmall baz = foo * bar;
    std::cout << static_cast<unsigned>(baz) << 'n'; // prints 25
}