9

これらのタイプがあるとしましょう:

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);

それはうまくいきます。しかし、この情報はコンパイル時にわかっているので、コンパイル時にアサートする方法を探しています。上記を静的アサートに変換する明らかな方法 (たとえば、g++ 4.2.2 で「整数型または列挙型以外の型へのキャストは定数式に表示できません」というエラーassertを与えると置き換えます)。BOOST_STATIC_ASSERT

携帯性はあまり重要ではありません。gcc 拡張機能やハッキーなテンプレート トリックを使用しても問題ありません。

更新:以前にほぼ同じ質問がされていることがわかりました: C++, statically detect base classes with different address? . 使用offsetof()することも唯一の有用な提案です。

4

2 に答える 2

4

「アドレスを変更せずに、関連する 2 つの型を互いにキャストできるようにしたい (つまり、多重継承がないこと、または基底クラスが派生クラスの最初の基底であること)」

あなたの「ie」は正しくありません。たとえば、がポリモーフィックでないDerived場合でも、 の最初の 4 バイトが vtable ポインターである可能性は十分にあります。Baseはい、(1) 最初のベース サブオブジェクトがオフセット 0 にあり、(2) vtable ポインターがオフセット 0 にある場合、C++ コンパイラはより簡単です。

これで、最初の部分を理論的にテストできました。offset_of(Base, first_member)標準レイアウト タイプでは、 と に違いはありませんoffset_of(Derived, first_member)。しかし実際にoffset_ofは、興味深い型では機能しません。UBです。そして、このチェックの要点は型をチェックすることなので、非標準レイアウトの型では確実に失敗するはずです。

于 2011-04-04T08:07:45.187 に答える
1

MSalters からの提案とC++ からの回答に基づいて、異なるアドレスを持つ基本クラスを静的に検出しますか? 、これが私が思いつく答えに最も近いものです。おそらく 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"

明らかに、これは不便で恐ろしいことです (メンバーを知っており、警告をオフにする必要があります)。

于 2011-04-04T17:43:22.807 に答える