meryngii.neta

今日も新たな"ネタ"を求めて。

配列を返す関数

C言語では配列を返す関数を作ることができない。

int a[100];

int f()[100] // エラー:関数は配列を返せない
{
	return a;
}

本当は

int[100] f() // エラー:構文エラー
{
	return a;
}

と書きたいところだが、これはC言語の奇妙な文法に合致しない。
複雑な宣言 - meryngii.neta
この現象は基本的C++でも同様である。上のようなコードを書くとエラーになる。
しかし、C++には参照がある。関数は参照を返すことができるし、配列の参照を取ることもできる。

int (&f())[100]
{
	return a;
}

...

f()[0] = 0; // OK

なんとこれはコンパイルすることができる。参照ってすごいや。
だがこの例は文法がいささか変態的である。できることなら次のように書きたいところだが、

int[100]& f() // エラー:構文エラー
{
	return a;
}

これはやはり構文エラーとなる。そこでtype_traitsのadd_referenceを使う。

#include <boost/type_traits/add_reference.hpp>

boost::add_reference<int[100]>::type f()
{
	return a;
}

コード量は長いが、この方が分かりやすい。

ポインタによる解決策

この問題においてはポインタを使って回避している方も多いだろう。

int* f()
{
	return a;
}

これはほとんどの場合でうまくいく。配列はポインタへの暗黙的キャストがされ、戻り値のポインタは配列と同じように[]で添え字でのアクセスができる。
しかしこれは先ほどの解決策と比べて問題がある。ポインタは配列の大きさの情報を持たない。

std::cout << sizeof(f());

普通は「sizeof(int)*(aの要素数)」の値が表示されることを望むだろうが、実際には「sizeof(int*)」の値が表示される。もちろん大きさに依存しないようにしたいときもあるだろうが、C++コンパイル時評価とは少し相性が悪い。