nullptrはc++11から追加された最も有益な機能の一つです。
今、このアーティクルを書いている時代は2015年ですが、未だにnullptrの使えない環境が存在します。信じられないでしょうが、例えばコンソールゲームの開発環境では未だにc++03相当の機能しかないコンパイラを相手にしなければいけないことがあります。
このアーティクルはプログラマとしての尊厳を奪われている一部の人向けに存在しているのであり、LLVMを使えるような、いわゆる普通の環境にいる人には全く意味の無いものであることを最初に宣言させて下さい。
nullptrが存在しなかったころnullを表すものは単に数値の0でした。
それは全く不十分なもので、単に0が書かれていてもコンパイラはポインタなのか数値なのかを把握できません。
1 2 3 4 5 6 7 8 9 10 |
#define NULL 0 void func(int); void func(char*); int main() { func(NULL); // 引数 int のほうが呼ばれる return 0; } |
CODE COMPLETEの一節にこんな言葉がります。
言語の中でプログラムするんじゃなく言語の中へプログラムしよう
__CODE COMPLETE 第二版
つまり言語が用意してくれていない機能や有効な思想は、言語に無いからといって諦めるのではなく、なんとか実現できる方法がないか考えようということです。
ではレガシーな環境でもnullptrが使えるようにオリジナルで実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const class { public: template <class T> // あらゆる型のポインタに operator T* const { // 変換できる return 0; // ゼロを返す } template <class C, class T> // あらゆる型のメンバのポインタに operator T C::*() const { // 変換できる return 0; // こちらもゼロ } private: void operator&() const; // アドレスは取得できない } nullptr; |
これで数値に代入できない型の完成です。
const 無名クラスで直接nullptrを定義してます。環境によっては名前をつけて別途インスタンスを生成しないとコンパイルエラーになるのでその場合はもうちょっとコードを書く必要があります。
ちなみにEffective C++ の第二版にこのnullptrの実装が書いてありましたが、第三版ではバッサリカットされています。
まとめ
- c++11より昔のコンパイラしか使えない環境ではnullptrは自作しよう
- もしくは戻り値にautoを書けるような最新の型推論を備えたコンパイラが使える環境に転職しよう