template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
return n;
}
取得できない部分は、このテンプレート関数のパラメーターです。n
配列内の要素の数として得られる配列をそこに渡すと、配列はどうなりますか?
まず、配列から値を取得しようとすると、最初の要素へのポインターが得られることを理解する必要があります。
int a[] = {1, 2, 3};
int *ap = a; // a pointer, size is lost
int (&ar)[3] = a; // a reference to the array, size is not lost
参照は、正確な型または基本クラスの型を使用してオブジェクトを参照します。重要なのは、テンプレートが参照によって配列を取ることです。パラメータとしての配列 (配列への参照ではない) は、C++ には存在しません。パラメータに配列型を指定すると、代わりにポインタになります。したがって、渡された配列のサイズを知りたい場合は、参照を使用する必要があります。関数テンプレートの場合と同様に、サイズと要素の型は自動的に推定されます。以下のテンプレート
template<typename T, size_t n>
size_t array_size(const T (&)[n]) {
return n;
}
前に定義した配列でa
呼び出すと、次の関数が暗黙的にインスタンス化されます。
size_t array_size(const int (&)[3]) {
return 3;
}
次のように使用できます。
size_t size_of_a = array_size(a);
少し前に作成したバリエーションがあります[編集:ここで誰かがすでに同じアイデアを持っていたことが判明しました]コンパイル時に値を決定できます。値を直接返す代わりに、以下に応じてテンプレートに戻り値の型を与えますn
。
template<typename T, size_t n>
char (& array_size(const T (&)[n]) )[n];
配列に要素がある場合、戻り値の型はサイズと要素の型n
を持つ配列への参照であると言います。これで、渡された配列のコンパイル時に決定されたサイズを取得できます。n
char
size_t size_of_a = sizeof(array_size(a));
char
要素を持つ配列にn
は sizeofがあるためn
、指定された配列内の要素の数も得られます。コンパイル時にできるので、
int havingSameSize[sizeof(array_size(a))];
関数は実際には呼び出されないため、定義する必要がないため、本体はありません。問題を少し解決できれば幸いです。
このように考えてください。たくさんの関数があるとします:
// Note that you don't need to name the array, since you don't
// actually reference the parameter at all.
size_t array_size(const int (&)[1])
{
return 1;
}
size_t array_size(const int (&)[2])
{
return 2;
}
size_t array_size(const int (&)[3])
{
return 3;
}
// etc...
これを呼び出すと、どの関数が呼び出されますか?
int a[2];
array_size(a);
配列サイズをテンプレート化すると、次のようになります。
template <int n>
size_t array_size(const int (&)[n])
{
return n;
}
コンパイラは、呼び出したパラメータに一致するバージョンの array_size をインスタンス化しようとします。したがって、10 個の int の配列で呼び出すと、n=10 で array_size がインスタンス化されます。
次に、型をテンプレート化するだけで、int 配列以外でも呼び出すことができます。
template <typename T, int n>
size_t array_size(const T (&)[n])
{
return n;
}
これで完了です。
編集:についてのメモ(&)
&
int 参照の配列 (不正) と int の配列への参照 (必要なもの) を区別するために、かっこを囲む必要があります。の優先順位[]
は よりも高いため&
、宣言がある場合:
const int &a[1];
演算子の優先順位により、int への const 参照の 1 要素配列になります。最初に適用したい場合は&
、括弧でそれを強制する必要があります:
const int (&a)[1];
これで、int の 1 要素配列への const 参照ができました。関数パラメーター リストでは、使用しない場合はパラメーターの名前を指定する必要がないため、名前を削除できますが、かっこはそのままにしておきます。
size_t array_size(const int (&)[1])
アレイには何も起こりません。テンプレート関数の署名を解決するために使用される未使用のパラメーターです。
テンプレート引数としても使用できませんが、それは別の問題です。
「constexpr」を持っていない私たちのために、結果をコンパイル時の const として取得する少し奇妙な方法:
#include <iostream>
namespace
{
template <size_t V>
struct helper
{
enum
{
value = V
};
};
template<typename T, size_t Size>
auto get_size(T(&)[Size]) -> helper < Size >
{
return helper < Size >() ;
}
template<typename T>
struct get_value
{
enum
{
value = T::value
};
};
}
int main()
{
std::cout << get_value<decltype(get_size("Foo bar baz"))>::value;
}