このコンストラクトの目的は、SomeType
正式にはオブジェクトが必要であるが、実際のオブジェクトを宣言したくない、または宣言できない場合に、タイプの名前のない偽のオブジェクトをエミュレートすることです。有効な用途があり、必ずしも未定義の動作を引き起こすわけではありません。
古典的な例は、クラスメンバーのサイズを決定することです
sizeof (*(SomeClass *) 0).some_member
または decltype の同様のアプリケーション
decltype((*(SomeClass *) 0).some_member)
上記の例のいずれも、未定義の動作を引き起こしません。評価されていないコンテキストでは、のような表現*(SomeClass *) 0
は完全に合法で有効です。
この手法は、8.3.5/12 のように、言語標準自体で説明目的で使用されていることも確認できます。
後続の戻り型は、declarator-id の前に指定するのがより複雑な型に最も役立ちます。
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
それよりも
template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
型との間の二項演算子の結果型のコンパイル時予測を実行するために(*(T*)0) + (*(U*)0)
式がどのように使用されるかを観察します。decltype
+
T
U
もちろん、繰り返しになりますが、そのようなトリックは、上記のように、評価されていないコンテキストで使用された場合にのみ有効です。
次のように、「null 参照」の初期化子として使用されることがあります。
SomeType &r = *(SomeType *) 0;
しかし、これは実際には何が合法であるかの境界を越えており、未定義の動作を引き起こします。
評価されたコンテキストで無効な「null lvalue」にアクセスしようとするため、特定の例にあるものは無効です。
&
PS C言語には、演算子と*
相互にキャンセルするという仕様の特有の部分もあります。つまり、それ&*(SomeType *) 0
は有効で、nullポインターに評価されることが保証されています。ただし、C++ には拡張されません。