C コンストラクトを置き換える C++ コンストラクトでの fizzer の投稿に続いて、ここに私の答えを書きます。
警告: 以下で提案されている C++ ソリューションは標準 C++ ではありませんが、g++ および Visual C++ の拡張であり、C++0x の標準として提案されています(これに関するFizzerのコメントに感謝します)。
Johannes Schaub - litb の回答では、別の C++03 準拠の方法が提供されていることに注意してください。
質問
C配列のサイズを抽出するには?
提案されたCソリューション
出典: C++ マクロが役立つのはいつですか?
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])
現在のスレッドで議論されている「優先」テンプレート ソリューションとは異なり、定数式として使用できます。
char src[23];
int dest[ARRAY_SIZE(src)];
定数式を生成できるテンプレート化されたソリューションがあるため、Fizzer には同意しません (実際、テンプレートの非常に興味深い部分は、コンパイル時に定数式を生成する機能です)。
とにかく、ARRAY_SIZE は C 配列のサイズを抽出できるマクロです。C++ のマクロについては詳しく説明しません。目的は、同等またはより優れた C++ ソリューションを見つけることです。
より良い C++ ソリューションですか?
次の C++ バージョンにはマクロの問題はなく、同じように何でもできます。
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
// return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
デモンストレーション
次のコードで示されているように:
#include <iostream>
// C-like macro
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])
// C++ replacement
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
// return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
int main(int argc, char **argv)
{
char src[23];
char * src2 = new char[23] ;
int dest[ARRAY_SIZE(src)];
int dest2[array_size(src)];
std::cout << "ARRAY_SIZE(src) : " << ARRAY_SIZE(src) << std::endl ;
std::cout << "array_size(src) : " << array_size(src) << std::endl ;
std::cout << "ARRAY_SIZE(src2) : " << ARRAY_SIZE(src2) << std::endl ;
// The next line won't compile
//std::cout << "array_size(src2) : " << array_size(src2) << std::endl ;
return 0;
}
これは出力されます:
ARRAY_SIZE(src) : 23
array_size(src) : 23
ARRAY_SIZE(src2) : 4
上記のコードでは、マクロがポインターを配列と間違えたため、間違った値 (23 ではなく 4) が返されました。代わりに、テンプレートはコンパイルを拒否しました。
/main.cpp|539|error: no matching function for call to ‘array_size(char*&)’|
* コンパイル時に定数式を生成できる * 間違った方法で使用した場合、コンパイルを停止できる
結論
したがって、全体として、テンプレートの引数は次のとおりです。
- コードのマクロのような汚染はありません
- 名前空間内に隠すことができます
- 間違った型評価から保護できます (メモリへのポインタは配列ではありません)
注: Microsoft による C++ 用の strcpy_s の実装に感謝します...これがいつか役に立てることはわかっていました... ^_^
http://msdn.microsoft.com/en-us/library/td1esda9.aspx
編集:ソリューションはC++ 0x用に標準化された拡張機能です
Fizzer は、これは現在の C++ 標準では無効であると正しくコメントしましたが、これはまったく真実でした (-pedantic オプションをオンにして g++ で検証できたため)。
それでも、これは現在 2 つの主要なコンパイラ (つまり、Visual C++ と g++) で使用できるだけでなく、次のドラフトで提案されているように、C++0x についても考慮されていました。
C++0x の唯一の変更点は、おそらく次のようなものです。
inline template <typename T, size_t size>
constexpr size_t array_size(T (&p)[size])
{
//return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
( constexprキーワードに注意してください)
編集 2
Johannes Schaub - litb の回答は、別の C++03 準拠の方法を提供しています。参照用にここにソースをコピーして貼り付けますが、完全な例については彼の回答にアクセスしてください(そしてそれをupmodしてください!):
template<typename T, size_t N> char (& array_size(T(&)[N]) )[N];
次のように使用されます。
int p[] = { 1, 2, 3, 4, 5, 6 };
int u[sizeof array_size(p)]; // we get the size (6) at compile time.
私の脳内の多くのニューロンは、array_size
(ヒント: N 文字の配列への参照を返す関数です) の性質を理解するために揚げました。
:-)