2013-02-28 13 views
7

少なくとも1つの仮想関数を持つクラスBaseと、これから単独で継承するDerivedクラスがある場合、(uintptr_t)derived - (uintptr_t)static_cast<Base*>(derived)は(派生標準レイアウトではありません。しかし、一般的な場合、これは必ずしも真実ではありません(例えば、複数の継承)。プライマリベースクラスを識別するための型特性

あるクラスが別のクラスの主な基底クラスであるかどうかを検出するために使用できる特性を記述できますか? ItaniumのABIから

有用セクション:それの仮想ポインタを共有する動的クラス、一意の基底クラス(もしあれば)について

http://refspecs.linux-foundation.org/cxxabi-1.83.html

主基地クラス

オフセット0。 非仮想動的基本クラスが存在する場合は、それが最初の(直接ベースクラスの順序で)。

ダイナミッククラス

仮想テーブルポインタを必要とするクラス(それまたはその塩基は、1つまたは複数の仮想メンバ関数または仮想基本クラスを持っているので)。

+4

あなたのテスト式は全く引用された定義と一致しません。基本サブオブジェクトのアドレスを調べていますが、ABIはvテーブル内のエントリの順序について議論しています。 –

+0

@BenVoigt:きれいに見つかった。 ABIへのリンクが本当にあるはずです。 –

+1

私はこの情報を使用することができたのは非常に不思議です。 –

答えて

8

これは、次の標準の一部になりますこれはstd::basesstd::direct_bases特性を経由して中止されたTR2の一部でした。ドラフト-TR2を含むコンパイラを使用している場合は、これをサポートしている可能性があります。例えばGCC 4.7.2で:

#include <demangle.hpp> 
#include <iostream> 
#include <tr2/type_traits> 

struct T1 { }; 
struct T2 { }; 
struct Foo : T1, T2 { }; 


int main() 
{ 
    std::cout << demangle<std::tr2::direct_bases<Foo>::type>() << std::endl; 
} 

この版画:

std::tr2::__reflection_typelist<T1, T2> 

(。デマングラは自分であり、あなたは他の場所でそれを見ている場合があります)

私はあなたが構築することができ、信頼適切な "多型であり、正確に0または1つの塩基を持っている" "自分自身の特性。

+0

恐ろしい!私は年齢のためにこれのようなものがほしいと思っていましたが、今は私が元々望んでいたものを覚えていません。 – GManNickG

+0

Itanium ABIの「1次ベース」は、C++標準の「直接ベース」とは異なります。複数のダイレクト・ベース・クラスを持つことは可能ですが、1つのベースのみをプライマリにすることができます。 – Praxeolitic

0

以下は、C++ 11にのみ役立つ何かを行う際の、徹底的にテストされていない試みです(実際にはは実際にはにはC++ 11の機能が必要ですが、

しかし、この特性は唯一のプロパティ「の主な基底クラスである」の推移閉包チェック:私はクラスが別の直接基底クラスであるかどうかを検証する非侵入的な方法を見つけ出すことができませんでしたがクラス。ここで

#include <type_traits> 

template<typename B, typename D, D* p = nullptr, typename = void> 
struct is_primary_base_of : std::false_type { }; 

template<typename B, typename D, D* p> 
struct is_primary_base_of<B, D, p, 
    typename std::enable_if< 
     ((int)(p + 1024) - (int)static_cast<B*>(p + 1024)) == 0 
     >::type 
    > 
    : 
    std::true_type { }; 

は一例です:

struct A { virtual ~A() { } }; 

struct B : A { }; 

struct C { virtual ~C() { } }; 

struct D : B, C { }; 

struct E : virtual A, C { }; 

int main() 
{ 
    // Does not fire (A is PBC of B, which is PBC of D) 
    static_assert(is_primary_base_of<A, D>::value, "Error!"); 

    // Does not fire (B is PBC of C) 
    static_assert(is_primary_base_of<B, D>::value, "Error!"); 

    // Fires (C is not PBC of D) 
    static_assert(is_primary_base_of<C, D>::value, "Error!"); 

    // Fires (A is inherited virtually by E, so it is not PBC of E) 
    static_assert(is_primary_base_of<A, E>::value, "Error!"); 

    // Does not fire (C is the first non-virtual base class of E) 
    static_assert(is_primary_base_of<C, E>::value, "Error!"); 
} 
+0

これは、ABIが何を話しているのかをテストしていない(質問も間違っていたので理解できる)。 –

+0

@BenVoigt:OK、私がテストすべきことを明確にすることができたら、答えを変えようとすることができます。そうでなければ、私はただそれを削除します –

+0

それは削除すべきではない有益な答えです。しかし、インスタンスレイアウトとvテーブルレイアウトについて議論したいかもしれません。私は定義されていない振る舞い(例えば、ポインターからメンバへの関数を整数型にキャスト)を使わずに、v表のレイアウトをチェックする方法は知らない。 –

関連する問題