Code Review Asked on February 2, 2021
This is a follow-up question for the previous questions about recursive functions, including A Summation Function For Arbitrary Nested Vector Implementation In C++, A recursive_count_if Function For Various Type Arbitrary Nested Iterable Implementation in C++, A recursive_count_if Function with Specified value_type for Various Type Arbitrary Nested Iterable Implementation in C++, A recursive_count_if Function with Automatic Type Deducing from Lambda for Various Type Arbitrary Nested Iterable Implementation in C++ and A recursive_count_if Function with Unwrap Level for Various Type Arbitrary Nested Iterable Implementation in C++. In order to test these functions for arbitrary nested iterables, I am trying to implement some arbitrary nested iterable generators to construct nested std::vector
s and nested std::array
s with the given parameters. The generator for std::array
case is named n_dim_array_generator
and another generator for std::vector
is named n_dim_vector_generator
. After trying to use if constexpr
syntax in the previous question, I found that it is possible to use the similar technique in n_dim_array_generator
function and n_dim_vector_generator
function.
The usage description
For example, auto test_vector = n_dim_vector_generator<2, int>(1, 3);
is expected to create a "test_vector" object which type is std::vector<std::vector<int>>
. The content of this test_vector
should as same as the following code.
std::vector<int> vector1;
vector1.push_back(1);
vector1.push_back(1);
vector1.push_back(1);
std::vector<std::vector<int>> test_vector;
test_vector.push_back(vector1);
test_vector.push_back(vector1);
test_vector.push_back(vector1);
There are four key part in the usage n_dim_vector_generator<2, int>(1, 3)
. The first number 2
represents the nested layers, the second parameter int
represents the type of base elements, the third parameter 1
represents the input element which would be filled in, and the fourth parameter 3
represents the element count in each layer.
In the n_dim_array_generator
function, the first parameter also represents the nested layers, but the parameter which represents the element count in each layer has been moved into the second one. Then, the third parameter represents the type of base elements and the fourth parameter represents the input element which would be filled in.
The experimental implementation
The experimental implementation of n_dim_vector_generator
function and n_dim_array_generator
function:
template<std::size_t dim, class T>
auto n_dim_vector_generator(T input, std::size_t times)
{
if (dim < 0)
{
throw std::logic_error("Dimension can not be set less than 0");
}
if constexpr (dim == 0)
{
return input;
}
else
{
std::vector<decltype(n_dim_vector_generator<dim - 1>(input, times))> output;
for (size_t i = 0; i < times; i++)
{
output.push_back(n_dim_vector_generator<dim - 1>(input, times));
}
return output;
}
}
template<std::size_t dim, std::size_t times, class T>
auto n_dim_array_generator(T input)
{
if (dim < 0)
{
throw std::logic_error("Dimension can not be set less than 0");
}
if constexpr (dim == 0)
{
return input;
}
else
{
std::array<decltype(n_dim_array_generator<dim - 1, times>(input)), times> output;
for (size_t i = 0; i < times; i++)
{
output[i] = n_dim_array_generator<dim - 1, times>(input);
}
return output;
}
}
Test cases
The test cases of n_dim_vector_generator
function and n_dim_array_generator
function are as below.
// n_dim_vector_generator function usage with recursive_reduce function and recursive_count_if function
auto test_vector1 = n_dim_vector_generator<3, int>(3, 2);
std::cout << "recursive_reduce output: " << recursive_reduce(test_vector1, 0) << std::endl;
std::cout << "recursive_count_if output: " << recursive_count_if<3>(test_vector1, [](auto& i) {return i == 3; }) << std::endl;
// n_dim_array_generator function usage with recursive_reduce function and recursive_count_if function
auto test_array1 = n_dim_array_generator<3, 2, int>(3);
std::cout << "recursive_reduce output: " << recursive_reduce(test_array1, 0) << std::endl;
std::cout << "recursive_count_if output: " << recursive_count_if<3>(test_array1, [](auto& i) {return i == 3; }) << std::endl;
The output of this test is as follows.
recursive_reduce output: 24
recursive_count_if output: 8
recursive_reduce output: 24
recursive_count_if output: 8
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++,
A recursive_count_if Function For Various Type Arbitrary Nested Iterable Implementation in C++,
What changes has been made in the code since last question?
The n_dim_vector_generator
function and n_dim_array_generator
function are the key part here.
Why a new review is being asked for?
I am not sure if it is a good idea to throw std::logic_error
in the situation of Dimension is set less than 0
. If there is any further possible improvement, please let me know.
dim < 0
Since dim
is a std::size_t
, it can never be negative, so this check is redundant.
If you know what the size of a vector is going to be up front, reserve()
space for the elements to avoid unnecessary memory operations.
emplace_back()
over push_back()
where possibleIn n_dim_vector_generator()
you can use emplace_back()
instead of push_back()
. It will probably not matter much with an optimizing compiler, but this way you avoid a move operation each time you add an item.
std::fill()
At least in n_dim_array_generator()
, you can use std::fill()
or std::fill_n()
to fill the array you created:
std::array<decltype(n_dim_array_generator<dim - 1, times>(input)), times> output;
std::fill(std::begin(output), std::end(output), n_dim_array_generator<dim - 1, times>(input));
return output;
You could also do this with n_dim_vector_generator()
if you resize()
the vector before filling it, but that causes unnecessary default construction of elements right before they are overwritten again, or you could combine it with std::back_inserter()
, like so:
std::vector<decltype(n_dim_vector_generator<dim - 1>(input, times))> output;
output.reserve(times);
std::fill_n(std::back_inserter(output), times, n_dim_vector_generator<dim - 1>(input, times));
return output;
Although sadly there is no std::back_emplacer()
.
Answered by G. Sliepen on February 2, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP