読者です 読者をやめる 読者になる 読者になる

上限と下限

C++

値が下限値を下回ったら、上限値を超えたら、という処理を以下のように書くことがよくありますが

// 下限
int a = 10;
for (;;) // ループ条件はとりあえずなんでもいい
{
    --a;
    if (a < 0)
        a = 0;
}
// 上限
int a = 0;
for (;;)
{
    ++a;
    if (a > 10)
        a = 10;
}

std::minとstd::maxを使うとスッキリ書けたりします。

// 下限
int a = 10;
for (;;)
{
    a = std::max(a - 1, 0);
}
// 上限
int a = 0;
for (;;)
{
    a = std::min(a + 1, 10);
}

でもこれだけだと、下限に達したとき、上限に達したときに何か処理をさせたい場合に不便なので
以下のように、minとmaxを拡張した関数を用意しておくと便利です。
ラムダ式がないとあまり便利と言えないので、ラムダ式がある前提で書きます。

// 下限
template <class T, class F>
inline const T& lower_limit(const T& a, const T& b, F f)
{
    return a > b ? a : ([&]() -> decltype((b)) { f(); return b; })();
}

// 上限
template <class T, class F>
inline const T& upper_limit(const T& a, const T& b, F f)
{
    return a < b ? a : ([&]() -> decltype((b)) { f(); return b; })();
}
// 下限
int a = 10;

bool b = true;
while (b)
{
    a = lower_limit(a - 1, 0, [&]{ b = false; }); // 下限に達したらループ終了
}
// 上限
int a = 0;

bool b = true;
while (b)
{
    a = upper_limit(a + 1, 10, [&]{ b = false; }); // 上限に達したらループ終了
}

だから早くラムダ式ほしいです。せつじつなんです。

あ、でもstd::min/maxだけでも地味に便利ですよ。



追記:
id:DigitalGhostさんとどようびさんにご指摘いただいた点を修正したバージョン

template <class T, class F>
inline const T& upper_limit(const T& a, const T& b, F f)
{
    return a < b ? a : (static_cast<void>(f()), b);
}

template <class T, class F>
inline const T& lower_limit(const T& a, const T& b, F f)
{
    return a > b ? a : (static_cast<void>(f()), b);
}

(f(), b)の括弧はいらないですが、(自分が)わかりやすいように付けてます。