やっさんの雑記

プログラミングでやってみたこととか

C++11で、ポインタ変数のもとの型と同じ型の変数を宣言する方法

みなさんお久しぶりです。
最近バイトとか研究とかでない個人的な開発をする余裕がなくなっていて、記事として公開できるネタが少なくてなかなか更新できていません(この状態は今後しばらく続くと思います)。

さて今回の記事は、「ポインタ変数のもとの型と同じ型の変数を宣言する方法」です。

具体的にどういうことかというと、下のようなコードを例に説明します。

int* hoge = new int[10]; // int*型の変数hoge
decltype(*hoge) fuga;    // fugaの型はこのままだとint&

このように単純に書いてしまうとint&型の変数が宣言されるが、やっぱりどうしてもint型の変数を宣言したい!ということです。

つまるところ、「ポインタ型からどうやってもとの型を取ってくるねん」ということになるのですが、天下のGoogleで検索すると、我らが救世主stackoverflowにほぼドンピシャな記事がありました(http://stackoverflow.com/questions/8696452/get-value-type-of-dereferencable-types)。

この記事で書かれているのは、C++template構造体を宣言して、その中でtypedefするみたいな方法です。

この方法で全然問題ないと思うんですが、この方法だと得られるのはあくまでtypedefされた型であって、もとの型ではないので、IntelliSenseで型名を表示すると汚らしい形式になって非常に気持ちが悪いです。

template<typename>
struct _dereference;

template<typename T>
struct _dereference <T*>
{
    typedef T type;
};

int* hoge = new int[10];
_dereference<decltype(hoge)>::type fuga; // 実質int型だけどIntelliSenseの表示は
                                         // _dereference<int*>::type

なので、このstackoverflowの回答のアイデアをもとに、IntelliSenseにやさしい(?)方法をとります。

typedefしてるのがIntelliSenseが汚らしい表示をする原因なので、typedefせずにダミーメンバをdecltypeすることで解決します。

template<typename>
struct _dereference;

template<typename T>
struct _dereference < T* > { T _dummy; };

#define dereference(T) decltype(_dereference<T>()._dummy)

...

int* hoge = new int[10];
dereference(decltype(hoge)) fuga; // 正真正銘int型のfugaになった!

少し一般的に、ポインタ型をdereferenceするためのマクロという形で書いてみました。

コードの実行に使うデータ量は手でfugaの型名を直打ちするのと全く変わらないです。
生成されるコード量もたぶん変わらないでしょう。
コンパイル時間は知りませんが。

2014/07/06修正

各コードの構造体の名前を変えました。