std::ranges::clamp
| ヘッダー <algorithm> で定義 |
||
| 呼び出しシグネチャ |
||
| template< class T, class Proj = std::identity, std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = |
(C++20以降) | |
値 v が範囲 [lo, hi] 内にある場合は v を返します。それ以外の場合は、最も近い境界値を返します。
lo が hi より大きい場合、動作は未定義です。
このページで説明されている関数のようなエンティティは、アルゴリズム関数オブジェクト(非公式にはニーブロイドとして知られている)です。つまり、
- これらのいずれかを呼び出す際に、明示的なテンプレート引数リストを指定することはできません。
- これらのいずれも実引数依存の名前探索には見えません。
- これらのいずれかが関数呼び出し演算子の左側の名前として通常の非修飾名探索によって見つかった場合、実引数依存の名前探索は抑制されます。
目次 |
[編集] パラメータ
| v | - | クランプする値 |
| lo, hi | - | v をクランプする境界 |
| comp | - | 投影された要素に適用する比較 |
| proj | - | v、lo、および hi に適用する投影 |
[編集] 戻り値
投影された v の値が投影された lo の値より小さい場合は lo への参照、投影された hi の値が投影された v の値より小さい場合は hi への参照、それ以外の場合は v への参照。
[編集] 計算量
最大2回の比較と3回の投影の適用。
[編集] 実装例
struct clamp_fn { template<class T, class Proj = std::identity, std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = std::ranges::less> constexpr const T& operator()(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}) const { auto&& pv = std::invoke(proj, v); if (std::invoke(comp, std::forward<decltype(pv)>(pv), std::invoke(proj, lo))) return lo; if (std::invoke(comp, std::invoke(proj, hi), std::forward<decltype(pv)>(pv))) return hi; return v; } }; inline constexpr clamp_fn clamp; |
[編集] 注意
std::ranges::clamp の結果を参照でキャプチャすると、パラメータのいずれかが一時オブジェクトであり、そのパラメータが返される場合に、ぶら下がり参照が発生します。int n = -1; const int& r = std::ranges::clamp(n, 0, 255); // r is dangling
v がどちらかの境界値と同値として比較される場合、境界値ではなく v への参照を返します。
投影が値で戻り、コンパイラが値で引数を受け取る場合、投影結果の型からコンパイラパラメータ型へのムーブがコピーと同等でない限り、この関数は投影とコンパイラの両方でプロジェクションを使用すべきではありません。std::invoke による比較が投影の結果を変更する場合、std::regular_invocable の意味論的要件(std::indirect_strict_weak_order によって包含される)により、動作は未定義です。
標準では、投影結果の値カテゴリが保持されることが要求されており、proj は v に対して一度しか呼び出せないため、投影結果が prvalue の場合、コンパイラは2回キャッシュしてムーブする必要があり、コンパイラへの2回の呼び出しが発生します。
- libstdc++ はこれに準拠しておらず、常に投影結果を lvalue として渡します。
- libc++ は以前、投影を2回実行していましたが、Clang 18 で修正されました。
- MSVC STL は以前、投影を2回実行していましたが、VS 2022 17.2 で修正されました。
[編集] 例
#include <algorithm> #include <cstdint> #include <iomanip> #include <iostream> #include <string> using namespace std::literals; namespace ranges = std::ranges; int main() { std::cout << "[raw] [" << INT8_MIN << ',' << INT8_MAX << "] " "[0" << ',' << UINT8_MAX << "]\n"; for (int const v : {-129, -128, -1, 0, 42, 127, 128, 255, 256}) std::cout << std::setw(4) << v << std::setw(11) << ranges::clamp(v, INT8_MIN, INT8_MAX) << std::setw(8) << ranges::clamp(v, 0, UINT8_MAX) << '\n'; std::cout << std::string(23, '-') << '\n'; // Projection function const auto stoi = [](std::string s) { return std::stoi(s); }; // Same as above, but with strings for (std::string const v : {"-129", "-128", "-1", "0", "42", "127", "128", "255", "256"}) std::cout << std::setw(4) << v << std::setw(11) << ranges::clamp(v, "-128"s, "127"s, {}, stoi) << std::setw(8) << ranges::clamp(v, "0"s, "255"s, {}, stoi) << '\n'; }
出力
[raw] [-128,127] [0,255] -129 -128 0 -128 -128 0 -1 -1 0 0 0 0 42 42 42 127 127 127 128 127 128 255 127 255 256 127 255 ----------------------- -129 -128 0 -128 -128 0 -1 -1 0 0 0 0 42 42 42 127 127 127 128 127 128 255 127 255 256 127 255
[編集] 関連項目
| (C++20) |
与えられた値のうち小さい方を返す (アルゴリズム関数オブジェクト) |
| (C++20) |
与えられた値のうち大きい方を返す (アルゴリズム関数オブジェクト) |
| (C++20) |
整数値が指定された整数型の範囲内にあるかを確認する (関数テンプレート) |
| (C++17) |
値を一対の境界値の間に制限する (関数テンプレート) |