Problem
This is a follow-up question for A Summation Function For Arbitrary Nested Vector Implementation In C++ and A Summation Function For Various Type Arbitrary Nested Iterable Implementation in C++. Besides the summation result, I am trying to get the element count in arbitrary nested iterable things. For example, there are three elements in std::vector<int> test_vector = { 1, 2, 3 };
, so the element count of test_vector
is 3
. The experimental implementation of recursive_count
is as below.
size_t recursive_count()
{
return 0;
}
template<class T> requires (!is_elements_iterable<T> && !is_iterable<T>)
size_t recursive_count(const T& input)
{
return 1;
}
template<class T> requires (!is_elements_iterable<T> && is_iterable<T>)
size_t recursive_count(const T& input)
{
return input.size();
}
template<class T> requires (is_elements_iterable<T> && is_iterable<T>)
size_t recursive_count(const T& input)
{
size_t output{};
for (auto &element : input)
{
output += recursive_count(element);
}
return output;
}
Some test cases of this recursive_count
template function.
// std::vector<int> case
std::vector<int> test_vector = {
1, 2, 3
};
auto recursive_count_result1 = recursive_count(test_vector);
std::cout << recursive_count_result1 << std::endl;
// std::vector<std::vector<int>> case
std::vector<decltype(test_vector)> test_vector2 = {
test_vector, test_vector, test_vector
};
auto recursive_count_result2 = recursive_count(test_vector2);
std::cout << recursive_count_result2 << std::endl;
// std::deque<int> case
std::deque<int> test_deque;
test_deque.push_back(1);
test_deque.push_back(1);
test_deque.push_back(1);
auto recursive_count_result3 = recursive_count(test_deque);
std::cout << recursive_count_result3 << std::endl;
// std::deque<std::deque<int>> case
std::deque<decltype(test_deque)> test_deque2;
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
auto recursive_count_result4 = recursive_count(test_deque2);
std::cout << recursive_count_result4 << std::endl;
All suggestions are welcome.
The summary information:
-
Which question it is a follow-up to?
A Summation Function For Arbitrary Nested Vector Implementation In C++ and
A Summation Function For Various Type Arbitrary Nested Iterable Implementation in C++
-
What changes has been made in the code since last question?
The previous questions are focused on summation operation, and I am trying to implement a
recursive_count
template function here. -
Why a new review is being asked for?
In my opinion, I am not sure the name of this function is good or not. I know there is a function
std::count
in STL which purpose is to count the elements that are equal to given specific value. If there is any better naming suggestion, please let me know.
Solution
No need for an overload that takes no parameters
Nothing calls recursive_count()
without parameters, so that overload is unnecessary.
Unnecessary requirements
You don’t need to require both is_elements_iterable<T>
and is_iterable<T>
, the former will already cover the requirements of the latter, and if you negate them then the latter covers the former. So the overloads should be:
template<class T> requires !is_iterable<T>
size_t recursive_count(const T& input)
{
return 1;
}
template<class T> requires (!is_elements_iterable<T> && is_iterable<T>)
size_t recursive_count(const T& input)
{
return input.size();
}
template<class T> requires is_elements_iterable<T>
size_t recursive_count(const T& input)
{
size_t output{};
for (auto &element : input)
{
output += recursive_count(element);
}
return output;
}
Naming
Indeed you already noticed that STL has a std::count
that does something different. However there is a function that does what you want for non-nested containers: std::size
. So consider naming your function std::recursive_size
.
Consider making more use of STL algorithms
You are implementing your own algorithms but you are not making use of STL’s algorithms. This can reduce the amount of code you write. For example, the last overload can be rewritten as:
template<class T> requires is_elements_iterable<T>
size_t recursive_count(const T& input)
{
return std::transform_reduce(std::begin(input), std::end(input), std::size_t{}, std::plus<std::size_t>(), [](auto &element){
return recursive_count(element);
});
}
Although I’m not sure this is more readable than your version.