プログラマーが特殊化のような奇妙なことを意図的に行っていないと仮定すると、reinterpret_cast
astd::pair<T1, T2> const &
を a に(理論上または実際に) 安全に使用できますか?std::pair<T1 const, T2> const &
std::pair<T1 const, T2>
3 に答える
そうすることは移植性がありません。
std::pair
要件は20.3項に規定されています。条項17.5.2.3は、次のことを明確にしています。
条項18から30および付録Dはクラスの表現を指定しておらず、クラスメンバーの指定を意図的に省略しています。実装は、条項18から30および付録Dで指定されたメンバー関数のセマンティクスを実装するために、必要に応じて静的または非静的クラスメンバー、あるいはその両方を定義できます。
これは、実装に次のような部分的な特殊化を含めることが合法であることを意味します(非常に可能性は低いですが)。
template<typename T1, typename T2>
struct pair<T1, T2>
{
T1 first;
T2 second;
};
template<typename T1, typename T2>
struct pair<const T1, T2>
{
T2 second;
const T1 first;
};
明らかにレイアウト互換ではありません。first
おそらく前に、および/またはルールの下で追加の非静的データメンバーを含めることを含む他のバリエーションsecond
も許可されます。
さて、レイアウトがわかっている場合を考えるのは少し興味深いです。Potatoswatterは、レイアウト互換ではないと主張するDR1334を指摘しましたが、標準は、とにかくほとんどの方法を取得できるようにするのに十分な保証を提供します。T
const T
template<typename T1, typename T2>
struct mypair<T1, T2>
{
T1 first;
T2 second;
};
mypair<int, double> pair1;
mypair<int, double>* p1 = &pair1;
int* p2 = reinterpret_cast<int*>(p1); // legal by 9.2p20
const int* p3 = p2;
mypair<const int, double>* p4 = reinterpret_cast<mypair<const int, double>*>(p3); // again 9.2p20
ただし、これは実際には指定されていない最初のメンバーであるstd::pair
ことがわからない限り9.2p20を適用できないため、機能しません。first
pair
は、標準のセクション 20.3.2 で次のデータ メンバーを持つように定義されています。
template <class T1, class T2>
struct pair {
T1 first;
T2 second;
};
これは、具象型T1
、T2
、pair<T1, T2>
およびpair<const T1, T2>
がそれぞれのデータ メンバーを持つことが保証されていることを意味します。
struct pair<T1, T2> {
T1 first;
T2 second;
};
struct pair<const T1, T2> {
const T1 first;
T2 second;
};
ここで、T1
とT2
が両方とも standard-layoutの場合、pair<T1, T2>
とpair<const T1, T2>
は両方とも standard-layout です。上で説明したように、DR1334まではレイアウトの互換性がありません(3.9p11) が、9.2p19reinterpret_cast
までにはそれぞれのメンバーT1
またはconst T1
最初のメンバーにすることができます。9.2p13 までにT2
2 番目のメンバーは最初のメンバーの後に配置する必要があり (つまり、より高いアドレスを持つ)、1.8p5 までに最初のメンバーの直後に配置する必要があります。
これを使用して確認できますoffsetof
(これは標準レイアウト タイプに対して定義されています)。
static_assert(offsetof(pair<T1, T2>, second) ==
offsetof(pair<const T1, T2>, second), "!");
pair<T1, T2>
とのレイアウトは同じであるためpair<const T1, T2>
、順方向にキャストし、結果を使用してメンバーにアクセスすることは、3.9.2p3 で有効です。
型のオブジェクトが
T
address にある場合、その値が address である型cvA
のポインターは、値がどのように取得されたかに関係なく、そのオブジェクトを指すと言われます。T*
A
したがって、reinterpret_cast
は の場合にのみ安全std::is_standard_layout<std::pair<T1, T2>>::value
ですtrue
。
実際の答えは、同じ表現を持つオブジェクトに再解釈キャストしているため、 const へのキャストは安全であるということです。ただし、その逆では、未定義の動作 (const から non-const) が発生します。
「理論的な」答えについては、C++ 標準では const/non-const オブジェクトの同一のビット単位の表現が保証されていないことに注意してください。const キーワードは、実装に依存する「概念的な constness」を保証します。