Следующее репо пытается взять std :: tuple и перебрать его для вывода различных значений, связанных с ним. Std :: tuple - это вершина, и конечным использованием этого будет вызов glEnableVertexArray и glVertexAttribPointer для элементов.Тип выведения основывается на существовании признака
До сих пор я выполнял итерации типов компонентов кортежа, а также находил смещение в каждом кортеже для каждого элемента. Однако я застрять с этой функцией:
template<class T>
void EmitAttribute(T const & v, int stride, int offset, int i)
{
std::cout << "Stride is "
<< stride
<< " element index "
<< i
<< " is at offset "
<< offset
<< " has 1 component "
<< std::endl;
}
Для основных типов (не-структуры), я хочу, чтобы излучать «имеет 1 компонент». Для элементов с признаком num_components я хочу испустить количество компонентов. Я пробовал:
template<class T, class S>
void EmitAttribute(T<S> const & v, int stride, int offset, int i)
{
...
<< " has " << T::num_components << " components "
...
}
Но он не компилируется. Как написать шаблон таким образом, что одна функция вызывается, когда T не имеет признака num_components, а другой вызывается, когда это происходит?
Полный репо:
#include <iostream>
#include <tuple>
template<class T, int C>
struct vec
{
typedef T value_type;
enum { num_components = C };
};
template<class T>
struct vec2 : vec<T, 2>
{
public:
T x, y;
vec2(T X, T Y) : x(X), y(Y) {}
};
template<class T>
struct vec3 : vec<T, 3>
{
public:
T x, y, z;
vec3(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
};
template<class T>
struct vec4 : vec<T, 4>
{
public:
T x, y, z, w;
vec4(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {}
};
namespace VertexAttributes
{
template<class T>
void EmitAttribute(T const & v, int stride, int offset, int i)
{
std::cout << "Stride is "
<< stride
<< " element index "
<< i
<< " is at offset "
<< offset
<< " has 1 component "
<< std::endl;
}
template<int index, class T>
int ElementOffset(T & t)
{
return static_cast<int>(reinterpret_cast<char*>(&std::get<index>(t)) - reinterpret_cast<char*>(&t));
}
template<int index, typename... Ts>
struct Emitter {
void EmitAttributes(std::tuple<Ts...>& t, unsigned size) {
EmitAttribute(std::get<index>(t), size, ElementOffset<index>(t), index);
Emitter <index - 1, Ts...> {}.EmitAttributes(t, size);
}
};
template<typename... Ts>
struct Emitter < 0, Ts... > {
void EmitAttributes(std::tuple<Ts...>& t, unsigned size) {
EmitAttribute(std::get<0>(t), size, ElementOffset<0>(t), 0);
}
};
template<typename... Ts>
void EmitAttributes(std::tuple<Ts...>& t) {
auto const size = std::tuple_size<std::tuple<Ts...>>::value;
Emitter < size - 1, Ts... > {}.EmitAttributes(t, sizeof(std::tuple<Ts...>));
}
}
int main()
{
typedef std::tuple<vec2<float>, vec3<double>, vec4<float>> vertexf;
typedef std::tuple<vec2<double>, vec3<float>, vec4<double>> vertexd;
typedef std::tuple<int, vec3<unsigned>, double> vertexr;
vertexf vf = std::make_tuple(vec2<float>(10, 20), vec3<double>(30, 40, 50), vec4<float>(60, 70, 80, 90));
vertexd vd = std::make_tuple(vec2<double>(10, 20), vec3<float>(30, 40, 50), vec4<double>(60, 70, 80, 90));
vertexr vr = std::make_tuple(100, vec3<unsigned>(110, 120, 130), 140.5);
VertexAttributes::EmitAttributes(vf);
VertexAttributes::EmitAttributes(vd);
VertexAttributes::EmitAttributes(vr);
return 0;
}
Почему бы не использовать только один класс и использовать 'T data [N]' как элемент данных, а не 'T data1, data2, data3, ... dataN'? Также исследуйте вариационный шаблон и 'std :: initializer_list'. – Nawaz
Я думаю, что вы предлагаете создать vec? Да, да. Что касается того, как данные хранятся для каждого элемента, у меня есть выбор. Я могу использовать std :: array или отдельные компоненты или объединение двух. Приятно иногда писать v [1], а иногда писать v.y. –
Robinson
Если вам нужны и хорошие имена, то вы можете иметь 'x()', 'y()', 'z()' как функции-члены, которые 'static_assert' определяют для проверки действительности, а затем используют соответствующий индекс для вернуть запрошенное значение. – Nawaz