Background
What I am trying to do is to implement some classes that represents geometry. Any instance of a geometry class has a method called vertices()
that returns a non-owning view of vertices. A geometry class can be expressed in terms of multiple other geometry classes, so the geometry class' vertices()
-method would ideally just do something like this (pseudocode):
vertices()
{
return join(part1.vertices(), part2.vertices(), part3.vertices());
}
subject to not copying nor moving vertices.
In C++20 this is something that I believe can be done with ranges & views but I can't figure out how to do it.
My attempt
#include <iostream>
#include <ranges>
#include <vector>
struct Vertex { float x, y, z; };
struct GeometryA {
auto vertices() {
return std::ranges::ref_view(v);
}
std::vector<Vertex> v {{0.0f, 0.0f, 1.0f}};
};
struct GeometryB {
auto vertices() {
return std::ranges::ref_view(v);
}
std::vector<Vertex> v {{0.0f, 1.0f, 0.0f}};
};
struct GeometryC {
auto vertices() {
// OK: All elements of vector are of same type
return std::vector{ a.vertices(), b.vertices(), std::ranges::ref_view(v)} | std::views::join;
}
GeometryA a;
GeometryB b;
std::vector<Vertex> v {{0.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}};
};
struct GeometryD {
auto vertices() {
// Compilation fails: Elements of vector have different types
return std::vector{ c.vertices(), std::ranges::ref_view(v)} | std::views::join;
}
GeometryC c;
std::vector<Vertex> v {{1.0f, 0.0f, 1.0f}};
};
int main() {
GeometryD d;
for(Vertex const& vertex : d.vertices()) {
// Should print {0,0,1} {0,1,0} {0,1,1} {1,0,0} {1,0,1}
std::cout << "{" << vertex.x << "," << vertex.y << "," << vertex.z << "} ";
}
return 0;
}
Compilation fails in GeometryD::vertices
since I am trying to deduce the template parameter T
of the outmost vector from the elements at initialization (c.vertices()
and std::ranges::ref_view(v)
) but these do not have the same type hence T
can't be deduced.
I am at a loss on how to approach this problem.
Question
Is it possible to use the standard ranges library to incrementally concatenate ranges?
I suppose I could gather all vertex-data directly or indirectly owned by a geometry class by using some recursive template-trickery and then just use std::views::join
once, but before I get my hands dirty with that I'd like to get some input on my current attempt.