この問題は、エラー メッセージで説明されているとおりです:float& ap[]
参照の配列を宣言します。これは、参照へのポインターと参照への参照が禁止されているのと同様に、C++ では有効な型ではありません。
合法である場合、ポインターの配列を考えることで、それが何を意味するかを考えることができます。参照は、いくつかの点で概念的にポインターに似ています。参照は別のエンティティを参照することを意図しており、参照がランタイム表現を必要とする場合、C++ 実装は通常ポインターを使用します。
したがって、ポインターの配列を関数に渡す場合は、初期化を構築する必要があります。
float a, b, c;
float *arr[] = {&a, &b, &c}; // or in fictional array-of-references syntax: float &arr[] = {a, b, c};
または、既に float の配列があり、それらの要素へのポインターの配列が必要な場合:
float a[3];
float *b[] = {&a[0], &a[1], &a[2]); // or in fictional array-of-references syntax: float &b[] = {a[0], a[1], a[2]};
おそらく、実際に必要なのは、参照によって配列を関数に渡して、関数が配列に書き込むことができ、変更が呼び出し元に表示されるようにすることです。(または単に配列のコピーを避けたいため)。通常、関数のパラメーターは値で渡され、参照で渡す方法&
はそこに固執することであるため、配列型に対して同じことを行いました。これは非常に優れた本能ですが、C++ には、それを台無しにするいくつかの問題があります。
1 つ目は、C++ での宣言の奇妙な構文です。「スパイラルルール」または「宣言は使用を模倣する」については他の場所で読むことができますが、それが&
変数名またはfloat
. float &arr[]
参照の配列です。アンパサンドを変数の近くに置くには、いくつかの括弧が必要ですfloat (&arr)[]
。配列への参照を宣言します。
次に、残念なことに、C++ は、配列とポインターをほとんど交換可能にすることを目的とした C からいくつかの奇妙な動作を継承しています。あなたの場合に関連する動作は、配列パラメーターを取る関数を宣言した場合です。
void foo(int arr[], int size);
言語は、型がポインターになるように「調整」されていると具体的に述べています。結果は次と同じです。
void foo(int *arr, int size);
これが意味することは、配列は値型のように振る舞わないということです。配列を「値で」渡そうとしても、配列の変更可能なコピーが関数に渡されません。代わりに、関数は効果的に配列を「参照によって」受け取ります。
2 番目の結果は、配列パラメータが完全な配列型を持つ必要がないことです。つまり、配列型は調整され、サイズはとにかく使用されないため、配列サイズを省略できます。これは、サイズを指定しない「配列パラメーター」を単純に配列への参照に変換する場合、&
. float (&arr)[10]
.
私の意見では、生の配列をパラメーターとして使用することは非常に望ましくありません。まず、型情報を破棄するため:
void foo(int arr[10]) { // same as void foo(int *arr)
int x = arr[9];
}
int bar[3];
foo(bar); // no compile error! the special array rules discarded the size of the array
また、生の配列は他の組み込み型と一貫性がないため、すべて値のセマンティクスがあります。これらの理由から、生の配列は避けるべきです。代わりにstd::array
、組み込み配列のすべての「特別な」ルールを回避するため、組み込み配列のように動作する which を使用できます。
void foo(std::array<int, 10> arr); // Takes arr by value, modifications will not be visible externally
std::array<int, 3> bar;
foo(bar); // compile error
動的なサイズの配列が必要な場合は、std::vector
代わりに使用できます。