patterncppMinor
Elementwise iterator adaptor
Viewed 0 times
adaptoriteratorelementwise
Problem
There are many C++ implementations of the Euclidean vector. I.e., a vector in what is typically a 3- or 4-dimensional space. Something along the lines of
It can of course also be a much more advanced implementation. Since we don't have a standard implementation, nearly every library provides their own. E.g., GLM, Assimp, FBX, etc.
It is common to work with ranges of vectors such as
Note how I can't use
This will further complicate the code.
I solve this problem by introducing an iterator adaptor called
This can be used to output all the coordinates
struct vec3f { float x, y, z; };It can of course also be a much more advanced implementation. Since we don't have a standard implementation, nearly every library provides their own. E.g., GLM, Assimp, FBX, etc.
It is common to work with ranges of vectors such as
std::vector (in computer graphics for instance). Furthermore, it is common to elementwise (by x, y, z) iterate through such a range. E.g.,std::vector uv_coordinates; // Given from 3rd party library
std::vector raw_uv_coordinates; // Used later for low-level transformations
for (const auto& position : positions) {
raw_uv_coordinates.emplace_back(position.x);
raw_uv_coordinates.emplace_back(position.y);
// The z-coordinate is discarded since it is not used.
}Note how I can't use
std::copy since there isn't a one-to-one mapping between uv_coordinates and raw_uv_coordinates. Say you have to support another vector type likestruct Vector4 { double data[4] };This will further complicate the code.
I solve this problem by introducing an iterator adaptor called
elementwise. It wraps an iterator to a container of vector elements. E.g.,auto first = elementwise(begin(uv_coordinates));
*first++; // Returns the x-coordinate of the 1st element.
*first++; // Returns the y-coordinate of the 1st element.
*first++; // Returns the z-coordinate of the 1st element.
*first++; // Returns the x-coordinate of the 2nd element.
...This can be used to output all the coordinates
std::copy(
elementwise(begin(uv_coordinates)),
elementwise(end(uv_coordinates)),
std::ostream_iterator{std::cout, ", "});elementwise gets information about the underlying vector type (vec3f, Vector4, etc.) through the vector_traits class. Consequently, vector_traits must be specialized for each vector type you Solution
I don't write C++, but one thing I've noticed is that your bracing style isn't consistent. You have the standard/expected C-style braces:
Then you have the one-liner style:
And then you have the Java-style braces:
Perhaps it's nitpicky, but you should strive to make your code look like it was written by one person - this looks like a Java and a C# programmer are fighting over which bracing style the C++ code base should be using:
I'd say just pick one, and stick to it ;)
struct is_const_iterator
{
typedef typename std::iterator_traits::pointer pointer;
static const bool value = is_const_pointer::value;
};Then you have the one-liner style:
template
auto elementwise( Iterator iterator )
{ return elementwise_iterator{iterator}; }And then you have the Java-style braces:
void decrement() {
if (!element) {
element = N;
--current;
}
--element;
}Perhaps it's nitpicky, but you should strive to make your code look like it was written by one person - this looks like a Java and a C# programmer are fighting over which bracing style the C++ code base should be using:
void decrement() {
if (!element) {
element = N;
--current;
}
--element;
}
void advance( difference_type n )
{
auto div = std::div(n, N);
current += div.quot; element += div.rem;
}I'd say just pick one, and stick to it ;)
Code Snippets
struct is_const_iterator
{
typedef typename std::iterator_traits<TIterator>::pointer pointer;
static const bool value = is_const_pointer<pointer>::value;
};template<int N, typename Iterator>
auto elementwise( Iterator iterator )
{ return elementwise_iterator<Iterator, N>{iterator}; }void decrement() {
if (!element) {
element = N;
--current;
}
--element;
}void decrement() {
if (!element) {
element = N;
--current;
}
--element;
}
void advance( difference_type n )
{
auto div = std::div(n, N);
current += div.quot; element += div.rem;
}Context
StackExchange Code Review Q#68879, answer score: 5
Revisions (0)
No revisions yet.