Если вы хотели, чтобы этот более простой подход обобщил его, чтобы вы могли извлечь из него больше пользы, а не адаптировать его к конкретной вещи. Тогда возникает вопрос: «Должен ли я создать новый класс для этой конкретной вещи?» но "я должен использовать мои утилиты?"; последнее всегда да. А утилиты всегда полезны.
Так сделайте что-то вроде:
template <typename T>
void check_range(const T& pX, const T& pMin, const T& pMax)
{
if (pX < pMin || pX > pMax)
throw std::out_of_range("check_range failed"); // or something else
}
Теперь у вас уже есть эта хорошая утилита для проверки диапазонов. Ваш код, даже без типа канала, уже можно сделать чище, используя его. Вы можете пойти дальше:
template <typename T, T Min, T Max>
class ranged_value
{
public:
typedef T value_type;
static const value_type minimum = Min;
static const value_type maximum = Max;
ranged_value(const value_type& pValue = value_type()) :
mValue(pValue)
{
check_range(mValue, minimum, maximum);
}
const value_type& value(void) const
{
return mValue;
}
// arguably dangerous
operator const value_type&(void) const
{
return mValue;
}
private:
value_type mValue;
};
Теперь у вас есть хорошая утилита, и вы можете просто сделать:
typedef ranged_value<unsigned char, 0, 15> channel;
void foo(const channel& pChannel);
И его можно использовать повторно в других сценариях. Просто вставьте все это в файл "checked_ranges.hpp"
и используйте его, когда вам нужно. Делать абстракции никогда не бывает плохо, а использование утилит не вредно.
Кроме того, никогда не беспокойтесь о накладных расходах. Создание класса просто состоит из запуска того же кода, который вы все равно сделали бы. Кроме того, чистый код должен быть предпочтительнее всего остального; производительность является последней проблемой. Как только вы закончите, вы можете заставить профилировщик измерить (не угадать), где медленные части.