これには複数の方法があると思います。私が理解していることから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;
}
選択する場合は、範囲がコンパイル時であっても、ランタイムメソッドを選択します。最適化が低くても、コンパイラーは同じコードを生成し、クラスバージョンよりもはるかに扱いにくく、間違いなく読みやすくなります。