浮動小数点配列へのポインターを取る関数があります。他の条件に基づいて、ポインタが実際に2x2 OR 3x3行列を指していることを知っています(実際、メモリは最初、フロートM [2] [2]などとして割り当てられていました)。重要なことは、関数の引数としてではなく、関数本体でこの決定を行いたいということです。
void calcMatrix( int face, float * matrixReturnAsArray )
{
// Here, I would much rather work in natural matrix notation
if( is2x2 )
{
// ### cast matrixReturnAsArray to somethingAsMatrix[2][2]
somethingAsMatrix[0][1] = 2.002;
// etc..
}
else if(is3x3)
{ //etc...
}
}
この問題により適切に対処するために、テンプレートやその他の手法を使用できることを認識しています。私の質問は、###コメントでそのようなキャストを作成する方法についてです。 C++での作業。
float (*somethingAsMatrix)[2] = (float (*)[2]) matrixReturnAsArray;
float *
は、floatの配列の最初の要素を指す可能性があり、その配列タイプにreinterpret_castableする必要があります。そして、そのキャストの結果はfloat [][]
の最初の要素を指す可能性があるため、その型にreinterpret_castableにする必要があります。あなたはそのようなキャストを構成し、直接行うことができるはずです
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray);
タイプfloat **
の引数は同じではないため、この方法で使用しないでください。
未定義の動作を回避するために、ポインタは実際の多次元配列から発生する必要があり、float*
を直接使用する場合は、多次元行列の最初の行以外にはアクセスできません。
void foo(float *f) {
f[3] = 10.;
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f);
arr[1][1] = 10.;
}
void main() {
float a[2][2];
foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined
float b[4];
foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined
}
float arr[2][2];
を指定しても、私が判断できる限り、&arr[0][1] + 1
が&arr[1][0]
と同じであることは保証されません。したがって、f[i*width + j]
を実行することで、1次元配列を多次元配列として使用できますが、多次元配列を1次元配列のように扱うことはできません。
誤って間違ったものを渡したり、間違ったreinterpret_castを実行したりするのではなく、C++のコンパイル時のタイプセーフを使用することをお勧めします。 raw配列を使用して型保証を取得するには、必要なraw配列型への参照を使用する必要があります。
void foo(float (&f)[2][2]) {}
void foo(float (&f)[3][3]) {}
値で配列を渡したい場合は、生の配列を使用できません。代わりにstd :: arrayのようなものを使用する必要があります。
void foo(std::array<std::array<float,2>,2> f) {}
void foo(std::array<std::array<float,3>,3> f) {}
Typedefの賢明な使用により、この種のキャストは常によりクリーンで扱いやすくなります。
typedef float Matrix_t[2][2];
Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray;
ただし、これがC++でCではない場合は、行列クラスを作成する必要があります。 (あるいは、もっと良いのは、オープンソースのものを探してください。)