Как получить VC ++ для доступа к указателю в виде 2D-массива

Я занимаюсь небольшим графическим программированием, и у меня есть двумерный массив (размер которого изменяется во время выполнения программы), который я храню с использованием 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 содержащий floats

Тем не менее, дома на моем компьютере с 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]'

0

Решение

Ну, это было весело; Я реализовал класс для обработки именно то, что я хотел.
Это не так безопасно, как хотелось бы, но я многому научился, делая это
Очень похоже на то, как я чувствовал, что должен реализовывать функциональность «синтаксический сахар-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
Ну хорошо, проверка во время выполнения должна быть достаточно хорошей

0

Другие решения


По вопросам рекламы [email protected]