Novice C++ programmers usually write a simple for loop if they want to count number of particular elements in the array – which could be entirely replaced by STL::count or STL::count_if.
std::count()
For example, given the following vector/array.
vector<int> nums({ 1, 2, 3, 4, 5, 3});
If we want to count the number of 3’s, we can use the std::count(). The first two parameters of the count() specify the range of the vector, and the third parameter is the target element.
cout << count(begin(nums), end(nums), 3); // prints 2.
The count() is defined in C++ header xutility and has the following template definitions:
// FUNCTION TEMPLATE count
template<class _InIt,
class _Ty>
_NODISCARD inline _Iter_diff_t<_InIt> count(const _InIt _First, const _InIt _Last, const _Ty& _Val)
{ // count elements that match _Val
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_Iter_diff_t<_InIt> _Count = 0;
for (; _UFirst != _ULast; ++_UFirst)
{
if (*_UFirst == _Val)
{
++_Count;
}
}
return (_Count);
}
#if _HAS_CXX17
template<class _ExPo,
class _FwdIt,
class _Ty,
_Enable_if_execution_policy_t<_ExPo> = 0>
_NODISCARD inline _Iter_diff_t<_FwdIt> count(_ExPo&& _Exec,
const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept;
#endif /* _HAS_CXX17 */
std::count_if()
What if you are looking to count something more complex e.g. the even numbers in the array/vector. We can use the std::count_if() which the third parameter is the specified predicate condition – you can pass in a lambda function.
vector<int> nums({ 1, 2, 3, 4, 5, 3});
cout << count_if(begin(nums), end(nums), [](auto &a) {
return a % 2 == 0;
}); // print 2 because there are 2 even numbers: 2 and 4.
The std::count_if is defined in C++ header file algorithm and its definition based on template is as follows:
// FUNCTION TEMPLATE count_if
template<class _InIt,
class _Pr>
_NODISCARD inline _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred)
{ // count elements satisfying _Pred
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_Iter_diff_t<_InIt> _Count = 0;
for (; _UFirst != _ULast; ++_UFirst)
{
if (_Pred(*_UFirst))
{
++_Count;
}
}
return (_Count);
}
#if _HAS_CXX17
template<class _ExPo,
class _FwdIt,
class _Pr,
_Enable_if_execution_policy_t<_ExPo> = 0>
_NODISCARD inline _Iter_diff_t<_FwdIt> count_if(_ExPo&& _Exec,
const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept;
#endif /* _HAS_CXX17 */
count() and count_if() are self explanatory which means you don’t need to even put comments. Using the std::count() and std::count_if() from the STL, you probably don’t need to write your own loop to count the elements in the STL containers anymore!
std::algorithms vs ranges
In modern C++, there are two variants of count_if, each coming from a different header:
- algorithm: Classic iterator‑based algorithm, since C++98.
- ranges: Range‑aware algorithm: since C++20.
Using algorithm the classic way to do count or count_if.
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6};
auto n = std::count_if(v.begin(), v.end(),
[](int x){ return x % 2 == 0; });
std::cout << n << '\n'; // prints 3
}
Using the ranges version:
#include <algorithm> // provides std::ranges::count_if in C++20
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6};
auto n = std::ranges::count_if(v,
[](int x){ return x % 2 == 0; });
std::cout << n << '\n'; // prints 3
}
since C++20 the Ranges library includes std::ranges::count in the
Why use the ranges version?
- No need to spell out begin(v) / end(v) — it deduces them for you.
- Accepts any range that meets the input_range concept, not just containers with iterators.
- Safer overload set: it avoids accidental pointer arithmetic errors that can occur with the classic iterator pair.
So if you are on C++20 or later, std::ranges::count is available right alongside std::ranges::count_if.
C/C++ Programming
- Understanding std::transform_reduce in Modern C++
- Implement a Lock Acquire and Release in C++
- Detecting Compile-time vs Runtime in C++: if consteval vs std::is_constant_evaluated()
- C++ Forward References: The Key to Perfect Forwarding
- Understanding dynamic_cast in C++: Safe Downcasting Explained
- C vs C++: Understanding the restrict Keyword and its Role in Optimization
- C++ Lvalue, Rvalue and Rvalue References
- C++ assert vs static_assert
- Why auto_ptr is Deprecated in C++?
- C++ What is the consteval? How is it different to const and constexpr?
- Tutorial on C++ std::move (Transfer Ownership)
- const vs constexpr in C++
- Tutorial on C++ Ranges
- Tutorial on C++ Smart Pointers
- Tutorial on C++ Future, Async and Promise
- The Memory Manager in C/C++: Heap vs Stack
- The String Memory Comparision Function memcmp() in C/C++
- Modern C++ Language Features
- Comparisions of push_back() and emplace_back() in C++ std::vector
- C++ Coding Reference: is_sorted_until() and is_sorted()
- C++ Coding Reference: iota() Setting Incrementing Values to Arrays or Vectors
- C++ Coding Reference: next_permutation() and prev_permutation()
- C++ Coding Reference: count() and count_if()
- C++ Code Reference: std::accumulate() and Examples
- C++ Coding Reference: sort() and stable_sort()
- The Next Permutation Algorithm in C++ std::next_permutation()
–EOF (The Ultimate Computing & Technology Blog) —
804 wordsLast Post: How to Reorder Data in Log Files using the Custom Sorting Algorithm?
Next Post: C++ Coding Reference: next_permutation() and prev_permutation()