Hatena::Diary

matsutakegohan1の日記

2007-10-06

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

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<class T, int N> 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め。

トラックバック - http://d.hatena.ne.jp/matsutakegohan1/20071006/1191643652
おとなり日記