template<typename TransformFunctor, typename BaseIterator>
class genesis::utils::TransformIterator< TransformFunctor, BaseIterator >
Iterator class that allows to transform an underlying iterator by applying a function to each element before dereferencing.
The constructor is used to set the transformation function. See also make_transform_iterator() and make_transform_range() for helper functions to easily create an instance.
This iterator takes the argument and return types of the TransformFunctor into account:
- If the TransformFunctor returns by value, we copy that value into an internal cache. This way, in cases where the iterator is dereferenced multiple times at the same iteration position, we do not need to apply the TransformFunctor each time.
- However, if the TransformFunctor returns by reference (const or non-const, but see also below), making a copy would be wasteful. Hence, in that case, we simply forward that reference here as well. This kind of transforming iterator is for example useful to efficiently select an entry from the underlying BaseIterator, e.g., an iterator over a
std::pair<>
could be transformed for selecting the first entry, without the need to copy that. If the TransformIterator is used that way, the underlying type does not even need to be copyable.
- Lastly, if the TransformFunctor returns by non-const reference, the underlying element can also be modified!
When using lambda functions for the TransformFunctor
, a bit of extra care is necessary to handle references correctly. In these cases, the return type has to be specified explicitly. For example, to select a particular entry, the following can be used:
// Some vector of vectors, e.g, a table of sorts.
std::vector<std::vector<LargeClass>> data;
// Fixed index of the element (i.e., the column when `data` is interpreted as a table)
// that we want to get from each of the rows of the above data.
size_t index = 2;
// Iterate the rows of data, and select a particular column index in each step.
// Have the lambda return those values per reference in order to avoid copies.
auto column_range = make_transform_range(
[index]( std::vector<LargeClass> const& values ) -> LargeClass const& {
assert( index < values.size() )
return values[index];
},
data
);
// Print the resulting values.
for( auto const& value : column_range ) {
std::cout << value << "\n";
}
Inspired by the Boost Transform Iterator (https://www.boost.org/doc/libs/1_66_0/libs/iterator/doc/html/iterator/specialized/transform.html) and the Intel TBB Transform Iterator (https://software.intel.com/content/www/us/en/develop/documentation/onetbb-documentation/top/intel-174-oneapi-threading-building-blocks-onetbb-developer-reference/iterators/transform-iterator.html). See also https://www.fluentcpp.com/2019/02/12/the-terrible-problem-of-incrementing-a-smart-iterator/ for a discussuion on the issue of calling the transform functor multiple times with caching. We went a bit above and beyond that, as explained above.
Definition at line 104 of file transform_iterator.hpp.