2012-11-13 2 views
9

私はこのような何か:明らかにC++ 11レンジベースforループはどのように配列サイズを認識しますか?

int my_array[5] = {1, 2, 3, 4, 5}; 
for (int &x : my_array) { 
    x *= 2; 
} 

C++ 11には、私の配列が唯一の5つの要素を持っていることを知っています。この情報はmy_arrayオブジェクトのどこかに格納されていますか?

もしそうなら、それが開発者として私に利用可能にされていない理由がありますか(それは?!?!?)? C++の開発者が常に彼らが扱っている配列の境界を知っていれば、世界の多くの問題が解決されるようです。

答えて

11

これは、言語が動作するために必要なものであり、コンパイラは実装する必要があります。明らかに、my_arrayの完全なタイプはint[5]であり(すなわち、サイズはタイプの一部である)、この情報は容易に利用可能である。これらは単純に(しかし、このアプローチを破るADLを含むキャッチあります)トリックを行うことができるように思われるが、人気の信念に反して

は、劇中のフリーstd::begin()/std::end()機能のない使用ありません。

+0

OK:

は、ここで例のサイズ機能です。では、my_array.sizeが存在しない理由は何ですか? – MrFox

+6

@suslik:もちろん、配列はクラス型ではないため、メンバ関数を持つことはできません。しかし、必要な値を生成する 'array_size'フリー関数テンプレートを簡単に書くことも、簡単に作成できる[' std :: extent'](http://en.cppreference.com/w/cpp/types/extent )。 –

+0

どのように私はこれについて長いこと知っていない私の人生を生き延びた...私はstd :: vectorを非難します:)。 – MrFox

5

いいえ、それはオブジェクトの一部ではありません。しかしそれはタイプの一部です。これは、配列宣言の5です。しかし、これは動作しません。

void f(int arr[5]) { 
    for(int& x: arr) { 
     // whatever 
    } 
} 

を配列の名前は、ここでその最初の要素へのポインタに崩壊するので、それは、引数の宣言にはサイズ情報を持っていないint *arrに相当しています。

+3

この例では、「崩壊」という用語を使用しません。この用語は、通常、多くの式で配列変数に行われる暗黙の変換に固有のものだと思います。 'int a [5]; a + 1; // decay'代わりに、標準で使用されている単語のように、ここで起こっていることを「調整」という用語で参照したいと思います。 'void foo(int a [5]); // 'adjust'と入力します。void foo(int * a) 'と同じです。そして私はその言葉を言うと皮肉な調子を使うのが好きです。 – bames53

+0

これはうまくいくでしょう。 'void f(int(&arr)[5]){...}' – balki

+0

参考までに、@ balkiの解決策は、未整理の配列リファレンスでは機能しません。 '(&arr)[5]'しかし、通常は、配列サイズをテンプレートパラメータとして使用して、汎用サイズの配列を作成することができます。https://stackoverflow.com/questions/26182907/range-based-for-loop-on-array-passed- to-non-main-function – andybuckley

6

標準C++の配列にbeginendを定義できます。配列のサイズは、その型でエンコードされます。

一般的な方法は、配列への参照を使用することです。

template<typename T, size_t N> 
size_t array_size(T (& const)[N]) 
{ 
    return N; 
} 
+6

これは 'std :: extent'とも呼ばれます。そして 'std :: begin'と' std :: end'は標準ライブラリの配列に対して既に定義されています。 –

関連する問題