This proposal introduces versions of the overload of the algorithm, which takes a searcher object instead of an iterator pair and (optionally) a predicate.
It was originally introduced for more performant specialized searching.
As customary in Ranges algorithms, this proposal also proposes Range-ified versions of the existing standard searchers, along with a concept for better capturing the semantic requirements of standard searchers.
1. Revision History
1.1. R1 (2026-08 mailing)
-
Fix wrong invocation of searchers in the given examples.
-
Add
-invocable requirement to conceptconst .searchable -
Change to
-based design to avoid lifetime issues. This makes the proposed searchers no longer constructible from iterator-sentinel pairs.views :: all -
This implies that the range-based searchers are sometimes move-only;
is thus adjusted to only requireconcept searchable .movable -
Additionally, adopt many design aspects employed by range adaptors, like the usage of
to store predicates and projections, and the addition ofmovable - box ,base () andpred () members.proj ()
-
-
Remove
overloads from searchers, following SG9 feedback in Brno (2026-06).operator ()( Range && ) -
Add interopability section and an optional additional change to the existing
.std :: search -
Add polls section.
1.2. R0 (2026-05 pre-Brno mailing)
-
Initial revision.
2. Background
is a very old standard algorithm, dating back to the inclusion of the original STL in 1994. The most basic shape of the algorithm takes two pairs of iterators representing haystack and needle, and returns the beginning position of the first occurrence of the needle sequence in the haystack sequence (or returns the end iterator of haystack if no occurrences are found). Optionally, the algorithm also takes a binary predicate to overwrite the equality comparison operation. The algorithm also has a variant that searches for copies of the same element instead of a provided needle range.
Several improvements and extensions have been applied to after its inclusion in the C++ standard. In the C++17 cycle, the introduction of parallel algorithms brings overloads to ; in the C++20 cycle alone, the merging of Ranges TS ([P0896R4]) into the standard brings with it the variant, which enables iterator-sentinel and ranges argument passing style instead of the traditional iterator pair style to the algorithm. Meanwhile, [P0202R3] also added the specifier to both variants of the algorithm, finally leading to its present form.
However, all of these modifications apply uniformly to most algorithms in the header; this proposal instead focuses on one specific enhancement that only applies to : the overload of the algorithm introduced by [N3905] (originally to Library Fundamentals TS v1, later merged into C++17). The original motivation for the inclusion of searchers was to allow more performant specialized search algorithms that precompute various statistics from the pattern to increase performance, as ’s normal overloads in general can only achieve a time complexity of using naive methods (where and are the length of the haystack and needle sequences, respectively). For instance, the standard implements the Boyer-Moore String Search Algorithm, which can achieve a worst-case running time of instead (requires some variation on the original 1977 version of the algorithm). In practice, using standard searchers often introduces significant speedup compared to normal invocations, at the cost of a larger memory footprint and longer initialization times on first invocation due to the need for precomputations.
Unfortunately, perhaps due to its late entrance to the standard, the overload is never included in either Boost.Ranges or range-v3, and as a result, the current Ranges library never included a overload with arguments. Given that nearly every other overload in the header has a corresponding version, and works ([P1813R0], [P3732R2]) have been underway to Range-ify the remaining algorithms too, it seems increasingly likely that the omission of this overload is an unintentional mistake.
This proposal thus proposes fixing this omission by introducing an overload for that accepts a algorithm instead of a second range. Furthermore, the C++23 algorithm introduced by [P2302R4] was specified as a convenience wrapper for , thus a overload is introduced for that algorithm too for API consistency.
3. Motivation
Current inconsistency in the API forces users to exit the Ranges world to use searchers and resort to using traditional STL algorithms instead, which is undesirable.
A before/after comparison of the feature is shown below:
// In C++26 std :: string haystack = "a quick brown fox jumps over the lazy dog" ; std :: string needle = "jump" ; std :: search ( haystack . begin (), haystack . end (), needle . begin (), needle . end ()); // OK std :: ranges :: search ( haystack , needle ); // OK, clear improvements to std::search std :: search ( haystack . begin (), haystack . end (), needle . begin (), needle . end (), []( auto a , auto b ) { return tolower ( a ) == b ; }); // OK std :: ranges :: search ( haystack , needle , []( auto a , auto b ) { return tolower ( a ) == b ; }); // OK std :: ranges :: search ( haystack , needle , {}, []( auto a ) { return tolower ( a ); }); // OK, better std :: search ( std :: execution :: par_unseq , haystack . begin (), haystack . end (), needle . begin (), needle . end ()); // OK std :: ranges :: search ( std :: execution :: par_unseq , haystack , needle ); // OK since C++26 std :: boyer_moore_searcher searcher ( needle . begin (), needle . end ()); std :: search ( haystack . begin (), haystack . end (), searcher ); // OK std :: ranges :: search ( haystack , searcher ); // Error! // After this proposal: std :: ranges :: boyer_moore_searcher searcher ( needle ); std :: ranges :: search ( haystack , searcher ); // Proposed OK
Since most Ranges algorithms use concepts to constrain their arguments instead of using template parameter names as an implicit named requirement, this proposal also follows this custom and introduces a concept for searchers that constraints their API, instead of relying on named requirements.
4. Design
4.1. What Is Being Proposed?
-
The following additional overloads for
andstd :: ranges :: search :std :: ranges :: contains_subrange
template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr auto ranges :: search ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr auto ranges :: search ( R && r , const Searcher & searcher , Proj proj = {}); template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr bool ranges :: contains_subrange ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr bool ranges :: contains_subrange ( R && r , const Searcher & searcher , Proj proj = {});
-
Concept
that captures the standard searcher requirementsstd :: searchable -
,std :: ranges :: default_searcher ,std :: ranges :: boyer_moore_searcher std :: ranges :: boyer_moore_horspool_searcher
4.2. Range-Based Searchers
The simplest version of a standard searcher is realized in , which acts as a thin wrapper around to make it follow the searcher API. The API for looks like this:
template < class ForwardIterator1 , class BinaryPredicate = equal_to <>> class default_searcher { public : constexpr default_searcher ( ForwardIterator1 pat_first , ForwardIterator1 pat_last , BinaryPredicate pred = BinaryPredicate ()); template < class ForwardIterator2 > constexpr pair < ForwardIterator2 , ForwardIterator2 > operator ()( ForwardIterator2 first , ForwardIterator2 last ) const ; };
There are several peculiarities in this API that make it unsuitable for the Ranges library, thus prompting this proposal to propose new versions of the standard searchers, similarly to the relation between and . For instance, all standard searchers' returns a pair of iterators after [P0253R1] identified that the end position of the needle inside the haystack is frequently useful for algorithms that are based on searchers. The Ranges library introduced directly for this purpose, and thus, that should be used as the return type instead.
The proposed API for looks like this:
template < forward_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity > requires view < V > class ranges :: default_searcher { public : constexpr explicit default_searcher ( V base , Pred pred = {}, Proj proj = {}); constexpr V base () const & requires copy_constructible < V > ; constexpr V base () && ; constexpr const Pred & pred () const ; constexpr const Proj & proj () const ; template < forward_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > constexpr subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const ; }; template < forward_range R , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity > default_searcher ( R && , Pred = {}, Proj = {}) -> default_searcher < views :: all_t < R > , Pred , Proj > ;
Essentially, the API for is a Range-ified version of , with the intention that (which calls ) is always equivalent to . It is for this reason that the concepts on have its arguments flipped.
The return type of has been changed to to represent the found range. This method will return if no occurrences of needle is found, if needle is empty, and the original (empty) range if the haystack is empty. This modification is consistent with the normal overload of .
The API for adds a type argument as the last template argument (that defaults to ), and adds a argument to the constructor. Apart from these changes, their API is identical to the default searchers (except requiring random-access iterators and ranges instead of forward ones). The argument is changed from the second argument to the last because of its default argument dependency on the projection. It is expected that most users will utilize CTAD to construct these searchers (i.e. ), so the positions of template argument are not that important anyways.
One thing to be noted here is that the existing searchers have a lifetime dependency on the underlying ranges; they will store the iterators from the provided range, and thus is only valid for use while the provided range is alive (or if it is a borrowed range). The proposed searchers utilize the existing Ranges mechanism of wrapping the given range in to eliminate this hazard.
4.3. Building A Searchers Concept
The concept itself does not fully capture the API proposed for the Range versions of searchers; this is because the proposed concept is iterator-based, so the Range constructor is not a required part of the searchers interface to reduce requirements on user-provided searcher types. The proposed specification for the concept is as follows:
template < class Searcher , class I , class S , class P = identity > concept searchable = movable < Searcher > && invocable < const Searcher & , I , S , P > && ranges :: forward_range < invoke_result_t < const Searcher & , I , S , P >>
It is worth noting that C++17 searchers are required to be copyable ([func.search.general]/2); due to the usage of , sometimes the new range-based searchers need to store an , which makes them move only. Therefore, the new concept only requires instead. The existing algorithm is specifically constraint to not rely on searchers being copyable ([alg.search]/12), so this relaxing should not cause issues.
Note that we deliberately use here since most implementations of non-trivial searchers are stateful.
4.4. constexpr And Return Type
It is worth noting that are not marked as currently, while on the other hand did support . On the other hand, the existing overload for searchers is marked as , making it incompatible with any non-trivial default searchers in compile-time invocation.
After investigating the current implementation of searchers among libstdc++, libc++ and MSVC STL, it seems that there is no inherent difficulty in making standard non-trivial searchers () -compatible, as most implementation only relies on a -enabled hash map that is already provided by [P3372R3] in C++26. However, given that as a whole still lacked specifications, the author feels that -ifying the searchers is best left to a future proposal that tackles for the entire header instead. The added overloads on and is marked in this proposal, as they can still work with third-party -enabled searchers. is marked following the existing practice of .
The return type for the new overloads of is specified as (i.e., copy the return type of the searcher’s ). It is possible to require convertible to here too, but the author thinks that this is an unnecessary limitation. The searcher’s return type is constrained to be a forward range by the concept .
4.5. Interopability With Existing Algorithms
During SG9 review in Brno (2026-06), the author is asked to investigate whether the new range-based searchers can be used with the existing algorithm, and whether the existing searchers can be used with .
For the former question, the current answer is no. Although as discussed above the algorithm is currently required to not depend on searchers being copyable, the specification unfortunately requires returning , which essentially limits the return type of searchers' to -like structures. The newly purposed range-based searchers' returns a , which does not have and members.
However, the author would like to purpose an additional change to that can bridge this gap: make the algorithm return instead. and most third-party pair-like structures should support the protocol, and thus such a change will not be breaking for any standard searchers and most third-party searchers; furthermore, also implements the protocol, and thus this change will make usable with the new range-based searchers (and return the begin iterator as usual). Of course, this will be a breaking change for searchers that have different behaviour for and , or pair-like return types that does not implement the tuple protocol, but the author estimate such searchers to be rare. This change is therefore presented as an optional additional change, with its wording section easily discarded if SG9/LEWG deemed the breakage to be too large.
For the latter question, the answer is also no, mainly because concept currently requires the return type of searchers' to be a forward range, while traditional searchers return a pair of iterators. Although iterator pairs are commonly used to denote a range, they are not accepted by the range concepts. It is possible to drop the return type requirement from (or require instead), and the author is happy to oblige if SG9/LEWG wants this change. It is worth noting that even with such a change this use case will not be fully supported as traditional searchers may not support iterator and sentinel with different types.
Finally, another question asked during the review is whether user needs to write two version of searchers from now on to make it usable for both and . If one of the above changes (or both) is adopted, then the answer is no, as the user can simply provide a or overload that will be compatible with both. Even if both changes are rejected, the user can simply overload on two and three arguments as always pass in a projection, so the author think that the risk of duplicating efforts are low.
4.6. Header Choice
The existing standard searchers live in , and all overloads of the algorithm live in .
This proposal proposes that the new overloads of and both still go into , which is consistent with other overloads of the two algorithms. The versions of the three existing standard searchers should also still go into , following the precedent of . The concept will go into , similar to other and concepts.
4.7. Feature-Test Macro Changes
Currently, both and use the same feature-test macro , and does not have a corresponding macro (its -edness is tracked by ). Also, does not have its own feature-test macro, and the author thinks that bumping for this seems a bit too huge.
This proposal ultimately decided to propose the following changes to feature-test macros:
-
A new FTM
for all Range versions of searchers__cpp_lib_ranges_searcher -
Do not bump the existing
; the author thinks that macro is more appropriate for direct functional changes to the searcher. This proposal also does not make any changes to the existing__cpp_lib_boyer_moore_searcher anywaystd :: boyer_moore_ [ horspool_ ] searcher -
A new FTM
for__cpp_lib_ranges_search (should track all overloads)std :: ranges :: search -
Bump the existing
FTM for__cpp_lib_ranges_contains (this FTM is also used byranges :: contains_subrange too)ranges :: contains
Note that also does not have its own FTM; if it is decided to pursue the additional interopability changes, the author do not think another separate FTM is needed; the change can be tracked by .
Of course, the author is happy to split the FTMs further (such as separate FTMs for each Range searcher) if LEWG requests.
4.8. Freestanding
After the adoption of [P2976R1] in C++26, the majority of (including all overloads of and ) are marked as freestanding. This proposal does not change anything in that regard, so the newly proposed overloads are also available in freestanding.
The searchers have a somewhat different status. is deliberately left out of freestanding by [P1642R11] as their common implementations rely on dynamic allocation, so their range versions are also not marked freestanding. is marked freestanding as it is just a thin wrapper around anyway. The concept is marked freestanding to maintain consistency with other parts of .
All feature-test macros added by this paper are marked freestanding, and all modified FTMs are already freestanding after the adoption of [P2198R7] and [LWG4286]. No existing features are moved to freestanding, so the freestanding-related FTMs are not changed.
4.9. Alternatives Considered
A possible less invasive change is to reuse the existing searchers, but only update with the new overloads. In that path, the concept will probably accept only an iterator type and test for .
However, such a change will not support range-based construction, not support projections on needles, and also not adapt to the new C++20 range/iterator model. The author thinks that requiring the user to write is strictly worse than introducing Range-ified versions of the searchers.
It has also been considered briefly to add a default argument to the argument of the algorithms; however, using here is meaningless, and other searchers all have different tradeoffs, so it seems unwise for the standard to specify one as the default choice.
4.10. Future Extensions
4.10.1. Parallel Overloads
After C++26 adopted [P3179R9], most of the algorithms in the namespace gained a parallel overload that accepts an execution policy as the first argument. Since searchers are born to increase the performance of searching, it seems natural to also add parallel overload to them to further increase efficiency.
However, most existing specialized algorithms are designed for sequential usage. Paralleled versions of the Boyer-Moore algorithm are certainly possible, but seem to require non-trivial handling of edge cases, such as when the pattern crosses the slicing boundaries. Given that C++17’s parallel STL library deliberately did not add an execution policy overload to the searcher version of , this proposal also does not add an execution policy overload to or .
A future parallel extension probably requires some kind of coordination between the algorithm and the searcher, so both the constructor and of the searcher probably should accept an execution policy argument (which also requires a new version of the concept ). However, such extensions are outside the scope of this proposal.
4.10.2. Searcher Overloads In More Algorithms
Currently, searchers are only accepted and used in . This proposal does a slight extension in this regard to make accept searchers too.
In the future, it can be envisioned that more algorithms can take advantage of searchers. For instance, may also accept a searcher that is constructed from and , and family may also benefit from more performant algorithms that search for single elements. However, such extensions are outside the scope of this proposal.
4.10.3. More Searchers
Finally, there are various attempts to add more searchers to the standard library, providing users with searchers that satisfy more tradeoff decisions. Popular choices include the famous Knuth-Morris-Pratt String-Searching Algorithm and Crochemore-Perrin Search Algorithm ([P0638R0]). Similar to Range algorithms, future extensions to searchers probably should only add types to (in particular from [P0638R0] can use instead). Though the author will not oppose adding versions too.
5. Implementation Experience
The author implemented this proposal in beman.range_searcher as part of the Beman Project. The implementation basically copies libc++'s searcher implementation and modify them to accommodate the new API. All modifications are straightforward, and no significant obstacles are observed.
6. Questions To Resolve
6.1. Questions for SG9
-
Should the searchers be templated on range types or iterator/sentinel types? - Resolved ✅ as the proposal switched to use
to solve lifetime issues.views :: all
6.2. Questions for LEWG
-
inherently does not require searchers to be copyable or movable; do we want to relax thestd :: search requirement inmovable ?searchable -
Should searchers'
be SFINAE-friendly (i.e., put the same value type requirements in theoperator () clause)?requires
7. Wording
The wording below is based on [N5054].
7.1. 17.3.2 Header < version > synopsis [version.syn]
In this clause’s synopsis, make the following modification, substituting by the date of adoption. All inserted new macro definition should be in places that respects the current alphabetical order of the synopsis.
#define __cpp_lib_ranges_contains 20XXYYL 202207L // freestanding, also in <algorithm> // [...] #define __cpp_lib_ranges_search 20XXYYL // freestanding, also in <algorithm> #define __cpp_lib_ranges_searcher 20XXYYL // freestanding, also in <functional>
7.2. 22.10.2 Header < functional > synopsis [functional.syn]
Modify the synopsis as follows:
// [...] namespace std { // [...] // [func.search], searchers // [...] template < class RandomAccessIterator , class Hash = hash < typename iterator_traits < RandomAccessIterator >:: value_type > , class BinaryPredicate = equal_to <>> class boyer_moore_horspool_searcher ; namespace ranges { template < forward_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity > requires view < V > class default_searcher ; // freestanding template < random_access_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < V > , Proj >>> requires view < V > && semiregular < range_value_t < V >> class boyer_moore_searcher ; template < random_access_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < V > , Proj >>> requires view < V > && semiregular < range_value_t < V >> class boyer_moore_horspool_searcher ; } // [...] }
7.3. 22.10.18.1 General [func.search.general]
Modify as follows:
Subclause [func.search] provides function object types ([function.objects]) for operations that search for a sequence
in another sequence[ pat_first , pat_last ) that is provided to the object’s function call operator. The first sequence (the pattern to be searched for) is provided to the object’s constructor, and the second (the sequence to be searched) is provided to the function call operator.[ first , last )
Each specialization of a class template specified in [func.search] shall meet the
Cpp17CopyConstructible and Cpp17CopyAssignableCpp17MoveConstructible and Cpp17MoveAssignable requirements. In addition, each specialization of class template,std :: default_searcher , andstd :: boyer_moore_searcher shall meet the Cpp17CopyConstructible and Cpp17CopyAssignable requirements. Template parameters namedstd :: boyer_moore_horspool_searcher
,ForwardIterator
,ForwardIterator1
,ForwardIterator2
,RandomAccessIterator
,RandomAccessIterator1
, andRandomAccessIterator2
BinaryPredicate of templates specified in [func.search] shall meet the same requirements and semantics as specified in [algorithms.general]. Template parameters named
shall meet the Cpp17Hash requirements ([tab:cpp17.hash]).Hash
The Boyer-Moore searcher implements the Boyer-Moore search algorithm. The Boyer-Moore-Horspool searcher implements the Boyer-Moore-Horspool search algorithm. In general, the Boyer-Moore searcher will use more memory and give better runtime performance than Boyer-Moore-Horspool.
Note: Editor’s Note: Insert the following subclause at the end of 22.10.18 Searchers [func.search]
7.4. 22.10.18.5 Range-based searchers [func.range.search]
7.4.1. 22.10.18.5.1 Class template default_searcher [func.range.search.default]
namespace std :: ranges { template < forward_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity > requires view < V > class default_searcher { public : constexpr explicit default_searcher ( V base , Pred pred = {}, Proj proj = {}); constexpr V base () const & requires copy_constructible < V > { return base_ ; } constexpr V base () && { return std :: move ( base_ ); } constexpr const Pred & pred () const ; constexpr const Proj & proj () const ; template < forward_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > constexpr subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > ; private : V base_ ; // exposition only movable - box < Pred > pred_ ; // exposition only movable - box < Proj > proj_ ; // exposition only } template < forward_range R , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity > default_searcher ( R && , Pred = {}, Proj = {}) -> default_searcher < views :: all_t < R > , Pred , Proj > }
constexpr explicit default_searcher ( V base , Pred pred = {}, Proj proj = {});
-
Effects: Constructs a
object, initializingdefault_searcher withbase_ ,move ( base ) withpred_ , andmove ( pred ) withproj_ .move ( proj )
constexpr const Pred & pred () const ;
-
Effects: Equivalent to:
return * pred_ ;
constexpr const Proj & proj () const ;
-
Effects: Equivalent to:
return * proj_ ;
template < forward_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > constexpr subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > ;
-
Effects: Equivalent to:
return ranges :: search ( first , last , ranges :: begin ( base_ ), ranges :: end ( base_ ), * pred_ , move ( proj2 ), * proj_ );
7.4.2. 22.10.18.5.2 Class template boyer_moore_searcher [func.range.search.bm]
namespace std :: ranges { template < random_access_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < V > , Proj >>> requires view < V > && semiregular < range_value_t < R >> class boyer_moore_searcher { public : explicit boyer_moore_searcher ( V base , Pred pred = {}, Proj proj = {}, Hash hf = {}); constexpr V base () const & requires copy_constructible < V > { return base_ ; } constexpr V base () && { return std :: move ( base_ ); } constexpr const Pred & pred () const ; constexpr const Proj & proj () const ; template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > ; private : V base_ ; // exposition only movable - box < Pred > pred_ ; // exposition only movable - box < Proj > proj_ ; // exposition only Hash hash_ ; // exposition only } template < random_access_range R , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> boyer_moore_searcher ( R && , Pred = {}, Proj = {}, Hash = {}) -> boyer_moore_searcher < views :: all_t < R > , Pred , Proj , Hash > ; }
explicit boyer_moore_searcher ( V base , Pred pred = {}, Proj proj = {}, Hash hf = {});
-
Preconditions: Let
beT . For any two valuesrange_value_t < V > andA of typeB , ifT , theninvoke ( pred , invoke ( proj , A ), invoke ( proj , B )) == trueishf ( invoke ( proj , A )) == hf ( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_searcher withbase_ ,move ( base ) withpred_ ,move ( pred ) withproj_ , andmove ( proj ) withhash_ .move ( hf ) -
Throws: Any exception thrown by the default constructor, copy constructor, or the copy assignment operator of
, theT expression, or the copy constructor orinvoke ofoperator () . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
constexpr const Pred & pred () const ;
-
Effects: Equivalent to:
return * pred_ ;
constexpr const Proj & proj () const ;
-
Effects: Equivalent to:
return * proj_ ;
template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > ;
-
Mandates:
isis_same_v < remove_cvref_t < projected_value_t < iterator_t < V > , Proj >> , remove_cvref_t < projected_value_t < I2 , Proj2 >>> true. -
Effects: Finds a subsequence of equal values in a sequence.
-
Returns:
, wheresubrange ( i , j ) andi is a pair of iterators such thatj
-
is the first iterator in the rangei such that for every non-negative integer[ first , last - ranges :: distance ( base_ )) less thann the following condition holds:ranges :: distance ( base_ ) invoke ( * pred_ , invoke ( proj2 , * ( i + n )), , andinvoke ( * proj_ , * ( ranges :: begin ( base_ ) + n ))) != false -
.j == ranges :: next ( i , ranges :: distance ( base_ ))
Returns if is true, otherwise returns if no such iterator is found.
-
Complexity: At most
applications of the predicate, and at most( last - first ) * ranges :: distance ( base_ ) applications of either projection.( last - first ) * ( ranges :: distance ( base_ ) + 1 )
7.4.3. 22.10.18.5.3 Class template boyer_moore_horspool_searcher [func.range.search.bmh]
namespace std :: ranges { template < random_access_range V , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < V >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < V > , Proj >>> requires view < V > && semiregular < range_value_t < R >> class boyer_moore_horspool_searcher { public : explicit boyer_moore_horspool_searcher ( V base , Pred pred = {}, Proj proj = {}, Hash hf = {}); constexpr V base () const & requires copy_constructible < V > { return base_ ; } constexpr V base () && { return std :: move ( base_ ); } constexpr const Pred & pred () const ; constexpr const Proj & proj () const ; template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > ; private : V base_ ; // exposition only movable - box < Pred > pred_ ; // exposition only movable - box < Proj > proj_ ; // exposition only Hash hash_ ; // exposition only } template < random_access_range R , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> boyer_moore_horspool_searcher ( R && , Pred = {}, Proj = {}, Hash = {}) -> boyer_moore_horspool_searcher < views :: all_t < R > , Pred , Proj , Hash > ; }
explicit boyer_moore_horspool_searcher ( V base , Pred pred = {}, Proj proj = {}, Hash hf = {});
-
Preconditions: Let
beT . For any two valuesrange_value_t < V > andA of typeB , ifT , theninvoke ( pred , invoke ( proj , A ), invoke ( proj , B )) == trueishf ( invoke ( proj , A )) == hf ( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_horspool_searcher withbase_ ,move ( base ) withpred_ ,move ( pred ) withproj_ , andmove ( proj ) withhash_ .move ( hf ) -
Throws: Any exception thrown by the default constructor, copy constructor, or the copy assignment operator of
, theT expression, or the copy constructor orinvoke ofoperator () . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
constexpr const Pred & pred () const ;
-
Effects: Equivalent to:
return * pred_ ;
constexpr const Proj & proj () const ;
-
Effects: Equivalent to:
return * proj_ ;
template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < V > , Pred , Proj2 , Proj > ;
-
Mandates:
isis_same_v < remove_cvref_t < projected_value_t < iterator_t < V > , Proj >> , remove_cvref_t < projected_value_t < I2 , Proj2 >>> true. -
Effects: Finds a subsequence of equal values in a sequence.
-
Returns:
, wheresubrange ( i , j ) andi is a pair of iterators such thatj
-
is the first iterator in the rangei such that for every non-negative integer[ first , last - ranges :: distance ( base_ )) less thann the following condition holds:ranges :: distance ( base_ ) invoke ( * pred_ , invoke ( proj2 , * ( i + n )), , andinvoke ( * proj_ , * ( ranges :: begin ( base_ ) + n ))) != false -
.j == ranges :: next ( i , ranges :: distance ( base_ ))
Returns if is true, otherwise returns if no such iterator is found.
-
Complexity: At most
applications of the predicate, and at most( last - first ) * ranges :: distance ( base_ ) applications of either projection.( last - first ) * ( ranges :: distance ( base_ ) + 1 )
7.5. 24.2 Header < iterator > synopsis [iterator.synopsis]
Modify the synopsis as follows:
// [...] namespace std { // [...] // [alg.req.ind.cmp], concept indirectly_comparable template < class I1 , class I2 , class R , class P1 = identity , class P2 = identity > concept indirectly_comparable = see below ; // freestanding // [alg.req.searchable], concept searchable template < class Searcher , class I , class S , class P = identity > concept searchable = see below ; // freestanding // [alg.req.permutable], concept permutable template < class I > concept permutable = see below ; // freestanding // [...] }
Note: Editor’s Note: Insert the following subclause between 24.3.7.5 Concept [alg.req.ind.cmp] and 24.3.7.6 Concept [alg.req.permutable]
7.6. 24.3.7.� Concept searchable [alg.req.searchable]
-
The
concept specifies the requirements of algorithms that interact with searchers (22.10.18 [func.search]) to search for a sequence in another sequence.searchable
template < class Searcher , class I , class S , class P = identity > concept searchable = movable < Searcher > && invocable < const Searcher & , I , S , P > && ranges :: forward_range < invoke_result_t < const Searcher & , I , S , P >>
7.7. 26.4 Header < algorithm > synopsis [algorithm.syn]
Modify the synopsis as follows:
// [...] namespace std { // [...] // [alg.contains], contains namespace ranges { // [...] template < execution - policy Ep , sized - random - access - range R1 , sized - random - access - range R2 , class Pred = ranges :: equal_to , class Proj1 = identity , class Proj2 = identity > requires indirectly_comparable < iterator_t < R1 > , iterator_t < R2 > , Pred , Proj1 , Proj2 > bool contains_subrange ( Ep && exec , R1 && r1 , R2 && r2 , Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr bool contains_subrange ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr bool contains_subrange ( R && r , const Searcher & searcher , Proj proj = {}); } // [...] // [alg.search], search // [...] template < class ForwardIterator , class Searcher > constexpr ForwardIterator search ( ForwardIterator first , ForwardIterator last , const Searcher & searcher ); namespace ranges { template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr auto search ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr auto search ( R && r , const Searcher & searcher , Proj proj = {}); } // [...] }
7.8. 26.6.4 Contains [alg.contains]
Add to the end of this clause:
template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr bool ranges :: contains_subrange ( I first , S last , const Searcher & searcher , Proj proj = {});
-
Returns:
! ranges :: empty ( ranges :: search ( first , last , searcher , move ( proj )))
template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr bool ranges :: contains_subrange ( R && r , const Searcher & searcher , Proj proj = {});
-
Returns:
! ranges :: empty ( ranges :: search ( forward < R > ( r ), searcher , move ( proj )))
7.9. 26.6.15 Search [alg.search]
Add to the end of this clause:
template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr auto ranges :: search ( I first , S last , const Searcher & searcher , Proj proj = {});
-
Effects: Equivalent to:
return searcher ( first , last , move ( proj ));
template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr auto ranges :: search ( R && r , const Searcher & searcher , Proj proj = {});
-
Effects: Equivalent to:
return searcher ( ranges :: begin ( r ), ranges :: end ( r ), move ( proj ));
8. Wording for Optional Additional Changes
Note: The wording below is for the standalone additional breaking change to .
8.1. 26.6.15 Search [alg.search]
Modify paragraph 11-12 as indicated:
template < class ForwardIterator , class Searcher > constexpr ForwardIterator search ( ForwardIterator first , ForwardIterator last , const Searcher & searcher );
-
Effects: Equivalent to:
return searcher ( first , last ). first ; return std :: get < 0 > ( searcher ( first , last )); -
Remarks:
need not meet the Cpp17CopyConstructible requirements.Searcher
9. Poll Results
9.1. SG9 Review, Brno (2026-06)
Poll 1: We want both and on the standardized searchers.
| Strongly Favor | Favor | Neutral | Against | Strongly Against |
| 2 | 0 | 4 | 1 | 0 |
-
Outcome: No consensus.
Poll 2: We want only on the standardized searchers.
| Strongly Favor | Favor | Neutral | Against | Strongly Against |
| 2 | 2 | 3 | 0 | 0 |
-
Outcome: Consensus in favor.
Poll 3: We want only on the standardized searchers.
| Strongly Favor | Favor | Neutral | Against | Strongly Against |
| 0 | 0 | 2 | 5 | 0 |
-
Outcome: Consensus against.