Or in any case to a very large portion of the programming population. And as much as we are “progressing” with dramatically changing C++98 from 11 to 17 and 20, that much it seems people at large are regressing in grasping the concepts of C++ standard library.

One of the key reasons is simple: abstract thinking is hard.
And C++ is based on the idea that fundamental abstractions and concepts if presented in a language are the best building blocks for software architecting and building art.
So, the C++ standard library is carefully selected and presented, as an large set of abstractions written in C++.
But here is a problem. Only portion of “normal” developers use C++. And even smaller portion do understand it.
For a newcomer, c++ std lib is one very large mountain to cross.
The other day, I had yet another one of the numerous needs (in my code) to find something in a string, from another string. And I know how to do this and I know how to use <algorithms>
part of the std namespace.
But let us assume it was you faced with this task. You the C++ beginner. To be the C++ “beginner” is a level high enough to be a master in some other programming languages. So you asked dear “Google”.
The code you pasted uses standard C strings. So “by the book” usage of std::find_first_of() will “of course” look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
int main() { char* s1 = "This sentence % contains % place holders."; char* s2 = "%"; char* f1 = std::find_first_of( s1, s1 + strlen(s1), s2, s2 + strlen(s2) ); printf("First place holder '%' found in %s, at position %d\n", s1, f1 - s1); } |
Working and absolutely horrible code. Yes it does show how to properly use std::find_first_of()
. It also makes every developer newcomer to C++ wishing NOT to learn C++.
If he or she tries the above, code, normal looking to the untrained eye, there will be warnings. Identical or very similar to this:

We could rectify this situation and considerably prolong this post in trying to do it in an pedagogical manner. But we wont.
But, compiler permitting the warnings, this code indeed works and supposedly shows the “genericity” of the std solutions because it does not require as mandatory the use of std::string
, etc. But in the same time, it is an epitome of the C++ anti marketing problem.
If I may help?
Above is one questionable peace of code. Partially because it has no sanity checking at all. It is just a display of the required way on how to use the std::find_first_of()
with C strings. And nothing else but C strings.
Slight detour
If that was the requirement here is the solution.
1 2 3 4 5 6 7 8 9 10 11 |
// standard C extern "C" int find_substring ( const char * string, const char * substring ) { size_t valid_len = strcspn(string, substring); if(valid_len != strlen(string)) return valid_len; else return -1 ; } |
Yes this works. It is fast and simple. Done. But it is not generic. Maybe you do not, but if you need a generic solution please read on.
Generic Solution
Then, I have decided it would be much better to provide a humble and simple helper function that will offer an immediate remedy and at the same time show, why is abstract thinking important and how that importance proves itself in practice.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// dbj_finder.h #pragma once #include <algorithm> /* (c) 2020 by dbj@dbj.org LICENCE CC BY SA 4.0 The requirement and the purpose: given two GENERIC sequences s1 and s2 find first element of s2 in s1 return the position relative to the s1 begining return -1 if s2 not found in s1 */ namespace dbj { template< typename S1, typename S2> inline auto find_first_of(const S1 & s1, const S2 & s2) { auto pos_ = std::find_first_of( std::begin(s1), std::end(s1), std::begin(s2), std::end(s2) ); return ( pos_ == std::end(s1) ? -1 : std::distance( std::begin(s1), pos_ ) ); } } |
One simple in-line helper providing an immediate remedy to the painful and repeatedly painful, usage of one std function. The usage of std::find_first_of()
suddenly becomes “normal” code. Let’s try first with string literals.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <cstdio> #include "dbj_finder.h" int main() { // C++ string literal is not 'const char *' const char format [] { "abra % ka % dabra" }; const char placeholder [] { "%" }; auto pos = dbj::find_first_of(format, placeholder); // this would also work // dbj::find_first_of("abra % ka % dabra", "%"); // /* process the return */ if (pos < 0 ) printf(R"(Placeholder "%s" not found in "%s")", placeholder, format); else printf(R"(Found placeholder "%s" in "%s", at position: %d)", placeholder, format, static_cast<int>(pos) ); } |
And that little helper is actually quite generic. It will work on anything that conforms to the C++ definition of a “sequence”. Thus also providing an rudimentary utility in checking if something is a proper sequence or not. Some user-defined abstraction perhaps. This line of code :
1 |
auto pos = find_first_of(first_sequence, second_sequence); |
Will indeed make the compiler to try and use “anything” you throw at it. Far beyond char arrays. But both sequences have to conform to C++ rules (hint: see the diagram above). Here is how you will use it with the two arrays of int’s.
1 2 3 4 5 6 |
const int ia [] { 1,2,3,4,5,6,7,8,9,0 }; const int sub_ia [] { 3,4,5 }; // is sub integer array inside integer array? int location_of_sub_ia = dbj::find_first_of(ia, sub_ia) ; |
I have deliberately not used here an SFINAE solution, to stop callers using this function with no legal sequences. I suggest instead we wait for C++20 constraints.
That will be a much more fun way vs trying to find and read the relevant sentence from pages of C++ compiler errors. And for me, C++20 delivers shorter and simpler code.
The whole C++17 program, is here.
This implementation is quite simple and good opportunity to learn C++ and other std namespace goodies. And also and importantly showing how a little bit of abstract thinking and knowledge of std namespace “composability”, makes std namespace so useful.
Just if you do know how to look at it.
I think this is a much better approach to explaining C++, vs not showing a working solution and forcing the understanding of the std lib first.
Similar kind of higher-level, helper wrappers can be applied to almost each and every function from the <algorithms>
part of the std lib.
Think abstract!