I'm looking to create a generic vertex data container with strong typing using templates. A partial interface would look like this:
template <VertexFormat VF>
class VertexData
{
public:
template<uint32_t I>
(StronglyTypedVertex*) vertices();
};
where VertexFormat is an enum, I is an index for different data streams, and StronglyTypedVertex is the resulting vertex data. Given vertex data stored as two separate streams of positions and texture coordinates (enum VertexFormat::Pos3_TexCoord2
), using the above vertex data container would look like this:
VertexData<VertexFormat::Pos3_TexCoord2> vertexData;
Vector3* positions = vertexData.vertices<0>();
Vector2* texCoords = vertexData.vertices<1>();
This seems like the kind of thing that type traits would work for. I've managed to get something working using a flat type trait with 2 properties, like so:
template<VertexFormat VF, uint32_t I>
struct VertexTraits
{
};
template<>
struct VertexTraits<VertexFormat::Pos3_TexCoords2, 0>
{
using Type = Vector3;
};
template<>
struct VertexTraits<VertexFormat::Pos3_TexCoords2, 1>
{
using Type = Vector2;
};
and then, the signature of VertexData::vertices
becomes:
template<uint32_t I>
VertexTraits<VF, I>::Type* vertices();
However, this isn't as convenient as I'd like because each permutation of vertex format and stream index requires its own type trait specialization. I was hoping to be able to do a single vertex trait with all streams in it, like so:
template<>
struct VertexTraits<VertexFormat::Pos3_TexCoords2>
{
using Stream0Type = Vector2; // Or some other similar declaration
using Stream1Type = Vector3;
};
I've tried nesting trait types with a Stream trait inside the VertexTrait, and I've tried using inheritance through a CRTP, but I haven't been able to get the syntax quite right for either case. What approach would work for this? Can it be done in a way that would introduce a static assert or compile-time error if a stream is used that wasn't defined (i.e.: Stream2Type in the above example)?