2011-04-04 16 views
7

のは、私はこれらの型を持っているとしましょう:ポインタキャストが簡単であるという静的アサートを行うにはどうすればよいですか?

struct A { 
    int a; 
}; 

struct B { 
    int b; 
}; 

struct C : public A, public B { 
    int c; 
}; 

C*ポインタは全く実際のアドレスを調整せずA*ポインタにキャストすることができます。しかしC*B*にキャストされている場合は、値を変更する必要があります。私が持っている2つの関連する型を、アドレスの変更なしに(つまり、多重継承がない、または基底クラスが派生クラスの最初の基底である)互いにキャストできることを確認したい。これは実行時にチェックすることができます。ように

assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000); 
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000); 

それは動作します。しかし、この情報はコンパイル時に知られているので、コンパイル時のアサーションを行う方法を探しています。上記を静的なアサーションに変換する明白な方法(たとえば、assertBOOST_STATIC_ASSERTに置き換えることは、g ++ 4.2で "整数型または列挙型以外の型へのキャストは定数式に現れません"というエラーを出す)

移植性あまり重要ではありませんgccの拡張機能、またはハックテンプレートのトリックを使用して、すべての罰金となり

更新:。。は、ほぼ同じ質問をする前に頼まれたことが判明:。C++, statically detect base classes with differing addresses?offsetof()を使用してもそこだけ便利な提案です。

+8

ニックピッチになりたくはありませんが、正確なメモリレイアウトは実装の詳細なので...なぜこの点に正確に興味がありますか? –

+0

私はBoost/lambdaライブラリにこれのためのものが含まれていると確信しています。私はそれを見なければならないだろうが、AlexandrescuとVandervoordeはこの分野のあらゆるトリックを公表している。 – sehe

+0

@Matthieu M.が提示している質問に本当に興味がある:キャストが簡単なことがあればどんな状況が重要か? (つまり、それが自明でない場合、コストはほとんど無視できる:導出されたポインタに定数を加え、条件が適切に実行されないと、壊れたメモリのようなものをデバッグしようとすると本当の苦痛にぶつかる) –

答えて

1

MSaltersの提案とC++, statically detect base classes with differing addresses?の回答に基づいて、ここで私が思いつく答えに最も近いものがあります。それはおそらく、GCC固有だし、基底クラスの一部メンバーを知っている必要があります。

#pragma GCC diagnostic ignored "-Winvalid-offsetof"  // To suppress warning. 
BOOST_STATIC_ASSERT(offsetof(C, a) == offsetof(A, a)); 
BOOST_STATIC_ASSERT(offsetof(C, b) != offsetof(B, b)); 
#pragma GCC diagnostic warn "-Winvalid-offsetof" 

は明らかにこれは不便で怖いの両方で(メンバーを知っていると警告をオフにする必要があります)。

4

"私は、アドレスの変更なしにタイプを互いにキャストすることができます(つまり、複数継承がない、または基底クラスが派生クラスの最初の基底であることなど) "

" ie "は正しくありません。 Baseがポリモーフィックでない場合でも、C++コンパイラは、(1)最初のベースサブオブジェクトがオフセット0にあり、(2)vtableポインタがオフセット0にある場合は、より簡単です。オッズ、および明確な、より良い選択肢はありません。

さて、最初の部分はoffset_of(Base, first_member)offset_of(Derived, first_member)に差はないであろう、標準レイアウトタイプで。理論的に試験することができる。しかし、実際には、offset_ofは動作しません。興味深いタイプのために、サブ。そして、このチェックの全体的なポイントはタイプをチェックすることです、従ってそれは非標準レイアウトタイプのために確実に失敗するはずです。

+1

"それは本当ではないため、確認できません"。私はそれが常に真実ではないので、私はチェックできるようにする必要があることを意味しました!さて、offsetof(C、a)のアイデアは非常に有望でしたが、gccは「静的でないデータメンバー 'NULLオブジェクトのA :: aへの無効なアクセス」について不平を言っています。 –

+0

実際、gccの申し立てはエラーではなく警告です。これは、Baseの最初のメンバーがわかっているときに機能します。それは何かです。ありがとう! –

+0

私はMSaltersのコメントを編集しました。「それは本当ではないので、あなたはそれを確認できません」と私は思っています。は正しくありません "。私はMSaltersがあなたの全体の発言が間違っていたと言っている可能性があるとは思わない。彼の次の文に基づいて、私は彼が "2つの関連する型をキャストできる"ということを意味したと思います。実際には "多重継承はありません..."と全く同じです。 – Quuxplusone

関連する問題