更新:「それは望まない、代わりにこれが欲しい」という提案に感謝します。それらは、特にやる気を起こさせるシナリオのコンテキストで提供される場合に役立ちます。それでも...善/悪に関係なく、私は「C++11で合法的に行うことができるはい」と「いいえそのようなことを行うことは不可能」を見つけるのが難しいことに興味を持っています。
いくつかのヘルパーメソッドを追加することのみを目的として、オブジェクトポインタを別のタイプとして「エイリアス」したいと思います。エイリアスは、基になるクラスにデータメンバーを追加できません(実際、それが発生するのを防ぐことができれば、それだけうまくいきます!)すべてのエイリアスは、このタイプのすべてのオブジェクトに等しく適用できます...型システムが次のことを示唆できる場合に役立ちます。エイリアスがおそらく最も適切です。
基になるオブジェクトにエンコードされた特定のエイリアスに関する情報はありません。したがって、型システムを「ごまかす」ことができ、それを注釈にすることができるはずです...コンパイル時にチェックされますが、最終的にはランタイムキャストとは無関係です。これらの線に沿った何か:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
内部的には、ファクトリメソッドは実際にNodeBase
クラスを作成し、同様のものを使用してreinterpret_cast
それをとして返しNode<AccessorFoo>*
ます。
これを回避する簡単な方法は、ノードをラップし、値によって渡されるこれらの軽量クラスを作成することです。したがって、キャストは必要ありません。ノードハンドルを取得してコンストラクターでラップするAccessorクラスだけです。
AccessorFoo foo (NodeBase::createViaFactory());
AccessorBar bar (foo.getNode());
しかし、私がそのすべてにお金を払う必要がなければ、私はしたくありません。これには、たとえば、ラップされたポインターの種類ごとに特別なアクセサー型を作成することが含まれます(AccessorFooShared、AccessorFooUnique、AccessorFooWeakなど)。これらの型付きポインターは、単一のポインターベースのオブジェクトIDに対してエイリアス化されることが望ましく、素敵な直交性。
では、元の質問に戻りましょう。
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
これを行うには、醜いかもしれないが「ルールを破る」ことはできない方法があるようです。ISO14882:2011(e)5.2.10-7によると:
オブジェクトポインタは、別のタイプのオブジェクトポインタに明示的に変換できます。70タイプ「pointertoT1」のprvaluevがタイプ「pointertocv T2」に変換されると、結果はstatic_cast(static_cast(v))になります。 T1とT2の両方が標準レイアウトタイプ(3.9)であり、T2のアライメント要件がT1のアライメント要件よりも厳密でない場合、またはいずれかのタイプが無効である場合。タイプ「pointertoT1」のprvalueをタイプ「pointertoT2」(T1とT2はオブジェクトタイプであり、T2のアライメント要件はT1の要件よりも厳密ではない)に変換して元のタイプに戻すと、元のタイプが生成されます。ポインタ値。他のそのようなポインタ変換の結果は指定されていません。
「標準レイアウトクラス」の定義を掘り下げると、次のことがわかります。
- タイプnon-standard-layout-class(またはそのようなタイプの配列)または参照の非静的データメンバーがなく、
- 仮想関数(10.3)と仮想基本クラス(10.1)がなく、
- すべての非静的データメンバーに対して同じアクセス制御(11節)があり、
- 非標準レイアウトの基本クラスはなく、
- 最も派生したクラスに非静的データメンバーがなく、非静的データメンバーを持つ基本クラスが多くても1つないか、非静的データメンバーを持つ基本クラスがない。
- 最初の非静的データメンバーと同じタイプの基本クラスはありません。
このようなもので作業することは、アクセサーまたはノードに仮想メソッドがない状態で私の手を少し縛るようなもののように聞こえます。それでも、C++11は明らかにstd::is_standard_layout
物事をチェックし続けなければなりません。
これは安全に行うことができますか?gcc-4.7で動作するように見えますが、未定義の動作を呼び出さないようにしたいと思います。