🗜️
[便利機能紹介] std::clamp
特定の値value
を範囲内[min_value, max_value]
に収めたい時には、以下のようなコードを使うと思います。
const int clamped_value(std::min(std::max(value, min_value), max_value));
C++17 からようやくstd::clamp
という関数が追加されました!
以下のように使います。
#include <algorithm>
const int clamped_value(std:clamp(value, min_value, max_value));
value
がmin_value
より小さい場合はmin_value
を、value
がmax_value
より大きい場合はmax_value
を、そうでなければvalue
を返します。
唯一注意しないといけないのは、この関数はmin_value
がmax_value
より小さいか同等という前提で動いています。min_value
がmax_value
より大きい場合は、エラーが返されずに未定義動作になります。つまり、コンパイラーの実装によって戻り値が変わります。
以下のように様々な実装が考えられますが、value
をどの順番でmin_value
とmax_value
と比較するかによって、結果が変わります。実際はテンプレート関数になっていると思いますが、ここではシンプルにするためにint
型に固定します。
int clamp1(int value, int min_value, int max_value)
{
return std::max(std::min(value, max_value), min_value);
}
int clamp2(int value, int min_value, int max_value)
{
return std::min(std::max(value, min_value), max_value);
}
int clamp3(int value, int min_value, int max_value)
{
return value < min_value ? min_value : max_value < value ? max_value : value;
}
int clamp4(int value, int min_value, int max_value)
{
return max_value < value ? max_value : value < min_value ? min_value : value;
}
std::cout << clamp1(0, 1, -1) << std::endl; // 1
std::cout << clamp2(0, 1, -1) << std::endl; // -1
std::cout << clamp3(0, 1, -1) << std::endl; // 1
std::cout << clamp4(0, 1, -1) << std::endl; // -1
実際にオンラインコンパイラーを使って、色々なコンパイラーでstd::clamp
でも同じケースを試してみた結果、「-1」が返されました。
std::cout << std::clamp(0, 1, -1) << std::endl; // -1
どちらにしても、予想外の値が返されるため、std::clamp
を使う前に、以下のようにmax_value
がmin_value
より大きいかをチェックしてください。
#include <algorithm>
#include <cassert>
assert(min_value <= max_value); // min_value > max_value の場合はここでエラーになります。
const int clamped_value(std::clamp(value, min_value, max_value));
是非使ってみてください!
Discussion