Я занимаюсь небольшим графическим программированием, и у меня есть двумерный массив (размер которого изменяется во время выполнения программы), который я храню с использованием openGL.
Поэтому, когда я иду к нему, все, что я получаю, это void
указатель назад.
Чтобы упростить логику, я хочу, чтобы компилятор сделал вид, что он есть, и использую его как двумерный массив (поскольку arr[i][j]
является более кратким и менее подверженным ошибкам, чем ptr[i * y + j]
).
Этот умный метод приведения, который я нашел, прекрасно работает в GCC (на машинах linux в универе):
Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);
Который в основном бросает блок памяти указатель openGL дал мне tess X tess
2D массив, и создает ссылку этого типа, чтобы указать на него.
Это позволяет мне получить доступ к памяти, как vertices[i][j]
,
Vertex
это просто typedef
издание struct
содержащий float
s
Тем не менее, дома на моем компьютере с Windows, VS’12 имеет шипение, жалуясь, что он требует целых чисел, где tess
написано, чтобы быть constant
(В частности; error C2057: expected constant expression
).
Понятия не имею почему.
Теперь я понимаю, что VS не поддерживает VLA, но я нет создание массив здесь, я создаю ссылка к чему-то, что я не знаю размер до времени выполнения.
Так что это не должно заботиться, если размер изменяется между вызовами функций, верно? Почему это не разрешено?
Не сдерживаться, я пытался использовать std::array
std::array<std::array<Vertex, tess>, tess>& vertices;
И кроме очевидного references must be initialized
этот тест не помог мне, потому что он все еще жаловался на expression must have a constant value
(в частности; error C2975: '_Size' : invalid template argument for 'std::array', expected compile-time constant expression
)
Я в недоумении, что попробовать здесь, я так гордился reinterpret_cast
и насколько все просто, и я был уверен, что не использую метод, противоречащий стандарту.
Я не хочу создавать std::vector
из указателя затем скопируйте данные из этого динамического массива обратно в расположение указателя, когда я закончу; это просто кажется неэффективным, когда блок памяти уже просто сидит!
Там нет никакого способа, чтобы создать вектор вокруг уже существующий блок памяти, есть? ..но это звучит глупо.
Я хочу посмотреть, можно ли это сделать, не сдаваясь и просто используя его как Vertex*
; Идеи?
Может кто-то просветить меня, почему он не работает в VS?
Есть ли что-то, что я могу сделать, чтобы заставить его работать (расширения / обновления для VS)?
VS’13 добавляет поддержку для этого?
Я тоже получаю ошибку C2087: 'vertices' : missing subscript
что я не могу объяснить.
А также эти другие ошибки, которые, кажется, показывают, отчаянно хочет VS tess
быть постоянным:
error C2466: cannot allocate an array of constant size 0
error C2540: non-constant expression as array bound
error C2440: 'initializing' : cannot convert from 'Vertex [1][1]' to 'Vertex (&)[][1]'
Ну, это было весело; Я реализовал класс для обработки именно то, что я хотел.
Это не так безопасно, как хотелось бы, но я многому научился, делая это
Очень похоже на то, как я чувствовал, что должен реализовывать функциональность «синтаксический сахар-esque», которая должна быть частью спецификации, до того, как я обнаружил jQuery.
По сути, вместо того, чтобы делать это.
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
Вам придется сделать это
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
Но кроме этого он работает без нареканий! : D
Сначала я написал только специализированный класс TwoDArray, но обнаружил, что у меня тоже есть несколько 3D-массивов.
Поэтому вместо реализации 3D-версии (которая вернула TwoDArray при детализации), я сделал что-то более общее и могу помочь с массивами любого количества измерений.
#include <Windows.h>
#include <iostream>
/*MultiDimensional Array Interpretation
has the compiler use a flat pointer reference as if it were a faceted array
C++11/GCC VLA-supporting equivalent:
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
using MDAI, <C++11 and MSVS compatible:
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
*/
template<class Type, unsigned int dimension>
class MDAI {
private:
Type* array;
//+1 to guard against zero-length-array
unsigned int bounds[dimension + 1];
public:
//unfortunately I can't use `unsigned int &(dimensions)[dimension]` to make it safe
//because of how operator[]() tries to construct its return value
/*constructor*/
MDAI(Type* array, unsigned int* bounds)
: array(array)
{
std::copy(bounds, bounds + dimension, this->bounds);
}
/*programmer usable constructor for typing of the dimensions, instead of having to declare an array*/
MDAI(Type* array, ...)
: array(array)
{
va_list arguments;
va_start(arguments, array);
for (int index = 0; index < dimension; ++index)
bounds[index] = va_arg(arguments, unsigned int);
va_end(arguments);
}
/*drills down one level into the multi dimensional array*/
MDAI<Type, dimension - 1> operator[](unsigned index) {
if (dimension < 1) {
std::cerr << "MDAI is not an array.\n";
throw 1;
}
if (index < 0 || index >= bounds[0]) {
std::cerr << "Index out of bounds.\n";
throw 1;
}
//figure out how many addresses to jump
for (unsigned int index2 = 1; index2 < dimension; ++index2)
index *= bounds[index2];
return MDAI<Type, dimension - 1>(array + index, bounds + 1);
}
/*'dereferences' the array to get a reference to the stored value*/
Type& operator*() {
if (dimension > 0) {
std::cerr << "MDAI is an array.\n";
throw 1;
}
return *array;
}
/*allows the compiler to automagically 'convert' the MDAI into whatever the user thinks it is*/
operator Type&() {
return **this;
}
/*makes assignment work automagically too!*/
MDAI<Type, dimension>& MDAI<Type, dimension>::operator=(Type value) {
**this = value;
return *this;
}
};
Тестирование трехмерного массива границ 2-4-3:
void main(unsigned int argC, char** argV) {
using namespace std;
int array[2][4][3] = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12}
},
{
{13, 14, 15},
{16, 17, 18},
{19, 20, 21},
{22, 23, 24}
}
};
//cast array to pointer, then interpret
MDAI<int, 3> mdai((int*)array, 2, 4, 3);
//testing correct memory access
cout << 15 << ' ' << mdai[1][0][2] << endl;
//testing modifcations using mdai are in array
mdai[0][2][1] = -1;
cout << array[0][2][1] << ' ' << mdai[0][2][1] << endl;
//testing modifications in array show up in mdai
array[1][3][2] = -23;
cout << -23 << ' ' << mdai[1][3][2] << endl;
//testing automatic type casting
cout << -15.0 << ' ' << mdai[0][0][1] * -7.5 << endl;
}
Это так же легко, как если бы я оставил его как ссылку на массив.
Для безопасности во время компиляции я хотел бы redeclare operator*()
как конкретно;
Type& MDAI<Type, 0>::operator*()
так что вы можете позвонить только на <X, 0>
Но я не мог понять это.
Точно так же получить operator[]()
появляться только для размеров больше 0
Ну хорошо, проверка во время выполнения должна быть достаточно хорошей