Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
std::ranges::clamp(3)	      C++ Standard Libary	 std::ranges::clamp(3)

NAME
       std::ranges::clamp - std::ranges::clamp

Synopsis
	  Defined in header <algorithm>
	  Call signature
	  template< class T, class Proj	= std::identity,

		    std::indirect_strict_weak_order<std::projected<const   T*,
       Proj>>
	  Comp								     =
       (since
			ranges::less					     >
       C++20)
	  constexpr const T&

	      clamp( const T& v, const T& lo, const T& hi,  Comp  comp	=  {},
       Proj proj
	  = {} );

	  If  the  value of v is within	[lo, hi], returns v; otherwise returns
       the nearest
	  boundary.

	  The behavior is undefined if lo is greater than hi.

	  The function-like entities described on  this	 page  are  niebloids,
       that is:

	    *  Explicit	template argument lists	cannot be specified when call-
       ing any of them.
	    * None of them are visible to argument-dependent lookup.
	    * When any of them are found by normal unqualified lookup  as  the
       name to the left
	      of  the function-call operator, argument-dependent lookup	is in-
       hibited.

	  In practice, they may	be implemented as function  objects,  or  with
       special compiler
	  extensions.

Parameters
	  v	 - the value to	clamp
	  lo, hi - the boundaries to clamp v to
	  comp	 - the comparison to apply to the projected elements
	  proj	 - the projection to apply to v, lo and	hi

Return value
	  Reference  to	 lo  if	the projected value of v is less than the pro-
       jected value of lo,
	  reference to hi if the projected value of hi is less than  the  pro-
       jected value of v,
	  otherwise reference to v.

Complexity
	  At most two comparisons and three applications of the	projection.

Possible implementation
	  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::for-
       ward<decltype(pv)>(pv)))
		      return hi;

		  return v;
	      }
	  };

	  inline constexpr clamp_fn clamp;

Notes
	  Capturing  the  result of std::ranges::clamp by reference produces a
       dangling
	  reference if one of the parameters is	a temporary and	that parameter
       is returned:

	int n =	-1;
	const int& r = std::ranges::clamp(n, 0,	255); // r is dangling

	  If v compares	equivalent to either bound, returns a reference	to  v,
       not the bound.

	  This	function should	not be used with both a	projection the returns
       by value	and
	  comparator that takes	arguments by value unless a move from the pro-
       jection result
	  type to the comparator parameter type	is equivalent to  a  copy.  If
       the comparison via
	  std::invoke  would  change the result	of projection, the behavior is
       undefined due to
	  the semantic requirements of std::regular_invocable (subsumed	by
	  std::indirect_strict_weak_order).

	  The standard requires	that the value category	of the result  of  the
       projection be
	  preserved, and proj can only be called on v once, which means	that a
       projection
	  result  that	is a prvalue has to be cached and moved	from twice for
       the two calls to
	  the comparator.

	    * libstdc++	does not conform to this and always passes the projec-
       tion result as an

lvalue.
	    * libc++ used to run the projection	twice, which was corrected  in
       Clang 18.
	    *  MSVC  STL used to run the projection twice, which was corrected
       in VS 2022 17.2.

Example
       // Run this code

	#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';
	}

Output:
	[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

See also
	  ranges::min returns the smaller of the given values
	  (C++20)     (niebloid)
	  ranges::max returns the greater of the given values
	  (C++20)     (niebloid)
	  in_range     checks  if  an integer value is in the range of a given
       integer type
	  (C++20)     (function	template)
	  clamp	      clamps a value between a pair of boundary	values
	  (C++17)     (function	template)

http://cppreference.com		  2024.06.10		 std::ranges::clamp(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=std::ranges::clamp&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help