配列の長さ(要素数)をコンパイル時に計算

892 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 22:19:28
配列の長さ(要素数)をコンパイル時に計算するにはどうしたらよいですか?
コンパイラの最適化レベルによらずにコンパイル時に計算になる例が欲しいです。

よろしくおねがいします。

903 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/23(日) 23:02:30

#include <cstddef> 
template<typename T, std::size_t N> 
char (&lengthof_helper_char_array(T (&a)[N]))[N]; 
#define lengthof(a) (sizeof(lengthof_helper_char_array(a)))

896 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 22:37:20
>892
最適化前提でいいなら、
template int len(T (&)[N]){return N;}
というのがわりと有名。

>892,895
sizeofを使うマクロに比べてこの関数がよいのは、配列以外をこの関数に
与えるとコンパイルエラーになること。

最適化無しで数値にできる方法は知らない。
Boostスレのほうがいいかもな。

912 名前: 903 [sage] 投稿日: 2007/09/23(日) 23:29:10
>>906
関数テンプレートの引数については >>896 といっしょね。
903 は戻り値で値を返すんじゃなくて元の配列と同じ長さの char 型の配列を
返すように宣言してる。 sizeof(char) は 1 なので、この配列に sizeof を
かければ元の配列の長さが得られる。 sizeof の引数の式は実際に実行される
ことがないので、定義は要らない。

typedef とか使ってもっと簡単なコードにしたいところだけど、 template のせいで
同じ記述を何度か繰り返すことになり、あんまりすっきりしない。

916 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 23:42:01
>>914
ありがとうございます。
もうすこしだけ教えていただけませんか?

理解の為、まず
char c3[] = {1,2,3};
char (&rc3)[3] = c3;
int main(){}
こう書いてみたらこれはコンパイルできました。

次に、
char (&f(int))[3]; // これは何.....
int main(){}
こう書いてみたら、これもコンパイルできてしまったんですが、
私は一体何を宣言したことになるのでしょうか?
917 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/23(日) 23:45:03
>>912
普通、配列を返す関数は作れないよね?
この宣言が許されるのが不思議だ...。

921 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 23:51:12
>>918-919
何がわかったの?

916の実験続き
char (&f(int))[3];
int main() {
return sizeof(f(10000));
}
は3が戻った。

次に、
char (&f(int))[3];
int main() {
f(100);
としてみたら、
undefined reference to `f(int)'
でリンクできなかった。とりあえずここまで。
922 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 23:53:50
こうしたらリンクできた。なんてこった。
こんな関数の定義方法があるのか!企画のどこに書いてあるんだろう?

char (&f(int))[3] {
static char x[3];
return x;
}

int main() {
f(100);

びっくりしました。ありがとうございました。みなさま。

925 名前: >>917-919 [sage] 投稿日: 2007/09/24(月) 00:08:19
おれが理解したのはこんな感じ
1.関数は配列を返すことは出来ないが、配列の参照ならば返すことができる。
その宣言方法は
char (&f())[3]; //char[3]の参照を返す関数fを宣言。

2.sizeof に関数呼び出しを与えても、関数呼び出しを行わない。返り血のサイズを返すのみ。
sizeof(f()); //この値は 3

これをtemplateで応用して上記1の配列サイズ(3)をNとし、Nはテンプレートのパラメータにする。
さらに、任意の型で仕様できる用に、typename Tもパラメータに加え、関数fの引数に与えオーバーロードさせる。
使いやすい様に sizeof(〜)全体を囲って #defineすれば>>903の出来上がり。

こんな形で実体の関数が使えるなんて知らなかった。sizeofめ。