Думаю, есть несколько способов сделать это. Из того, что я понимаю, n
может принимать только определенный диапазон чисел. Для этого вы можете запретить запуск конструктора:
template <typename T, T Min, T Max>
class ranged_type_c
{
public:
typedef T value_type;
ranged_type_c(const value_type& pX) :
mX(pX)
{
check_value();
}
const value_type& get(void) const
{
return mX;
}
operator const value_type&(void) const
{
return get();
}
// non-const overloads would probably require a proxy
// of some sort, to ensure values remain valid
private:
void check_value(void)
{
if (mX < Min || mX > Max)
throw std::range_error("ranged value out of range");
}
value_type mX;
};
Может быть более конкретным, но это идея. Теперь вы можете зажать диапазон:
struct foo_c
{
foo_c(ranged_value_c<int, 0, 100> i) :
x(i)
{}
int x;
};
Если вы передадите значение, которое не лежит в диапазоне от 0 до 100, вышеприведенное будет выдано.
Во время выполнения, я думаю, ваша оригинальная идея была лучшей:
template <typename T>
const T& check_range(const T& pX, const T& pMin, const T& pMax)
{
if (pX < pMin || pX > pMax)
throw std::range_error("ranged value out of range");
return pValue;
}
struct foo
{
foo(int i) :
x(check_range(i, 0, 100))
{}
int x;
}
И это все. То же, что и выше, но 0 и 100 можно заменить вызовом некоторой функции, которая возвращает действительный минимум и максимум.
Если вы в конечном итоге используете вызов функции для получения допустимых диапазонов (рекомендуется, чтобы помеха была минимальной, а организация выше), я бы добавил перегрузку:
template <typename T>
const T& check_range(const T& pX, const std::pair<T, T>& pRange)
{
return check_range(pX, pRange.first, pRange.second); // unpack
}
Чтобы разрешить такие вещи:
std::pair<int, int> get_range(void)
{
// replace with some calculation
return std::make_pair(0, 100);
}
struct foo
{
foo(int i) :
x(check_range(i, get_range()))
{}
int x;
}
Если бы я выбрал, я бы выбрал методы времени выполнения, даже если диапазон был во время компиляции. Даже при низкой оптимизации компилятор будет генерировать один и тот же код, и он будет гораздо менее неуклюжим и, возможно, чище читать, чем версия класса.