2011-11-01 15 views
22

次のコードは、スタックに割り当てられた配列のサイズを返します。このC++コードは何を意味していますか?

template<typename T, int size> 
int siz(T (&) [size]) 
{ 
    return size; 
} 

を私は、構文のまわりで私の頭をラップすることはできません。 特にT (&) [size]部分...

+1

[なぜC++でこのような混乱した方法で定義された配列への参照ですか?](http://stackoverflow.com/questions/6456253/why-is-reference-to-array-defined-in-そのような混乱のような方法で) – sharptooth

+7

全く重複しない –

+0

エイリアステンプレートを使用して読みやすくなるような別名と書くことができます。 –

答えて

24

しかし、私は構文の周りを頭で囲むことはできません。特にT (&) [size]部分...

その部分は配列への参照です。任意のCおよびC++ 宣言を解読するための"right-left rule"があります。

関数テンプレートは、指定された関数引数からテンプレート引数の型を推定するので、この関数テンプレートは配列の型と要素数を推定し、その数を返します。

関数は、ポインタ型または参照型ではなく、値によって配列型を受け入れることはできません。

void foo(int*); 

int x[10]; 
int* p = x; // array decay 
foo(x);  // array decay again 

アレイ減衰がアレイの元の種類を破壊し、従って、それの大きさが失われる:参照は、その最初の要素(別名、配列減衰)へのポインタの配列の暗黙的な変換を回避するために使用されています。

C++ 03の関数呼び出しであるため、戻り値はコンパイル時定数ではない(つまり、戻り値はテンプレート引数として使用できません)。 C++ 11では関数は、コンパイル時の定数を返すためにconstexprでマークすることができます。

template<typename T, size_t size> 
constexpr size_t siz(T(&)[size]) { return size; } 

配列要素がわずかに異なる形式を使用することができるC++ 03でのコンパイル時の定数としてカウントを取得するには:それは(「左右ルールが」理解することができる場所です)同じ参照ツーアレイ引数とが、char(&)[size]の戻り値の型を持つ関数テンプレートを宣言上記で

template<class T, size_t size> 
char(&siz(T(&)[size]))[size]; // no definition required 

int main() 
{ 
    int x[10]; 
    cout << sizeof siz(x) << '\n'; 
    double y[sizeof siz(x)]; // use as a compile time constant 10 
} 

。関数呼び出しは実行時に決して起こらないので、関数テンプレートsizの定義は不要です。 sizeof siz(x)は、が ""と呼ばれた場合、基本的にはを返します。

定数コンパイル時間として配列の要素数を取得する古いC/C++の方法がある:

#define SIZ(arr) (sizeof(arr)/sizeof(*(arr))) 
+0

は、&の周りの括弧ですか? –

+0

@JasonS - 括弧は 'T 'への参照の配列のように見えないようにする必要があります – Flexo

+0

ああ、ok ...そして'(T&)[size] 'はどちらもうまくいかないでしょうか? (申し訳ありませんが、Cコンパイラを起動しておかないでください) –

4

は(テンプレートが異なる型名で使用することができる)型名となる機能をIt's外側からのサイズです。次に、このサイズを返します。

スタック関数は、多くの場合、sizeを使用します。これは、この関数で要求するスタックサイズのサイズを示す整数です。 &はスタックTのどのサイズを意味するのかをテストします。

7

T (&) [size]は配列への参照です。次のプログラムは有効ではありませんので、それは、参照する必要があります:int sz(int *)と同じです

test.cc: In function ‘int sz(int*)’: 
test.cc:6:5: error: redefinition of ‘int sz(int*)’ 
test.cc:3:5: error: ‘int sz(int*)’ previously defined here 

int sz(int [4])ので:

#include <iostream> 

int sz(int *) { std::cout << "wtf?" << std::endl; return 0; } 


int sz(int [4]) { std::cout << "4" << std::endl; return 0; } 

int main() { 
    int test[4]; 
    sz(test); 
} 

このプログラムでは、とのコンパイルに失敗します。

T& [size]はそうでなければ違法である参照の配列のように見えるので、括弧はここで曖昧さを排除する必要があります。

template<typename T, int size> 
int sz(T (&arr) [size]) 

を配列に名前arrを与えるために:パラメータはあなたが書くでしょう匿名でなかった場合、通常

。この例では、関心のあるすべてのサンプルコードが推測されたサイズであるため、匿名の引数は未使用の引数についての警告を回避します。

関連する問題