如何逐步连接范围?
How to incrementially concatenate ranges?
背景
我想做的是实现一些表示几何的 classes。几何体的任何实例 class 都有一个名为 vertices()
的方法,该方法 returns 是一个非拥有的顶点视图。几何 class 可以用多个其他几何 classes 来表示,因此几何 class' vertices()
方法理想情况下只会做这样的事情(伪代码):
vertices()
{
return join(part1.vertices(), part2.vertices(), part3.vertices());
}
以不复制或移动顶点为前提。
在 C++20 中,我相信可以用范围和视图来完成,但我不知道该怎么做。
我的尝试
#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;
}
编译在 GeometryD::vertices
中失败,因为我试图从初始化时的元素(c.vertices()
和 std::ranges::ref_view(v)
)中推导出最外层向量的模板参数 T
,但是它们没有相同的类型,因此无法推导出 T
。
我不知道如何解决这个问题。
问题
是否可以使用标准范围库来递增地连接范围?
我想我可以通过使用一些递归模板技巧来收集几何体 class 直接或间接拥有的所有顶点数据,然后只使用 std::views::join
一次,但在我动手之前,我想就我当前的尝试获得一些意见。
背景
我想做的是实现一些表示几何的 classes。几何体的任何实例 class 都有一个名为 vertices()
的方法,该方法 returns 是一个非拥有的顶点视图。几何 class 可以用多个其他几何 classes 来表示,因此几何 class' vertices()
方法理想情况下只会做这样的事情(伪代码):
vertices()
{
return join(part1.vertices(), part2.vertices(), part3.vertices());
}
以不复制或移动顶点为前提。
在 C++20 中,我相信可以用范围和视图来完成,但我不知道该怎么做。
我的尝试
#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;
}
编译在 GeometryD::vertices
中失败,因为我试图从初始化时的元素(c.vertices()
和 std::ranges::ref_view(v)
)中推导出最外层向量的模板参数 T
,但是它们没有相同的类型,因此无法推导出 T
。
我不知道如何解决这个问题。
问题
是否可以使用标准范围库来递增地连接范围?
我想我可以通过使用一些递归模板技巧来收集几何体 class 直接或间接拥有的所有顶点数据,然后只使用 std::views::join
一次,但在我动手之前,我想就我当前的尝试获得一些意见。