0

私は少しグラフィックプログラミングを行っており、openGL を使用して保存する 2 次元配列 (プログラムの実行中にサイズが変化する) を持っています。
そのため、アクセスしようとすると、返されるのはvoidポインタだけです。

ロジックを簡単にするために、コンパイラに 2D 配列であると偽らせて、2D 配列として使用するようにします (arr[i][j]は より簡潔でエラーが発生しにくいためptr[i * y + j])。


私が見つけたこの巧妙なキャスト方法は、GCC (uni の Linux マシン上) でうまく機能します。

Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
    glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);

これは基本的に、openGL が提供したメモリ ポインターのブロックをtess X tess2D 配列にキャストし、その型の参照を作成してそれを指すようにします。
これにより、のようにメモリにアクセスできますvertices[i][j]sを含む
Vertex単なるtypedefedですstructfloat

ただし、私の Windows マシンの自宅では、VS'12 はヒッシーなフィット感を持っており、(具体的には ; )tessに書かれている整数が必要であると不平を言っています。 理由がわかりません。constanterror 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]'

4

1 に答える 1

0

楽しかったです。必要なものを正確に処理するクラスを実装しました。
それは私が望むほどタイプセーフではありませんが、
jQuery を発見する前に、仕様の一部であるべきだと感じていた javascript の構文糖のような機能を実装するのと同じように、それを行うことで多くのことを学びました。

基本的に、これを行うことができる代わりに。

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;
    }
};

境界の 3 次元配列のテスト 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;
}

配列参照として残していた場合と同じくらいシームレスです。

operator*()コンパイル時の安全のために、具体的には次のように再宣言したかったのです。
Type& MDAI<Type, 0>::operator*()
そのため、<X, 0> でしか呼び出すことが
できませんでしたが、わかりませんでした。
同様にoperator[]()、0 より大きい次元に対してのみ表示さ
れるようになります。

于 2014-09-13T13:33:47.677 に答える