8

少なくとも1つの仮想関数を持つクラスBaseがあり、これから単独で継承するクラスDerivedが(uintptr_t)derived - (uintptr_t)static_cast<Base*>(derived)ある場合、Derivedは標準レイアウトではありませんが、(Itanium ABIによって)ゼロであることが保証されます。ただし、一般的なケースでは、これは必ずしも正しいとは限りません(例:多重継承)。

あるクラスが別のクラスのプライマリ基本クラスであるかどうかを検出するために使用できるトレイトを作成することは可能ですか?

Itanium ABIの便利なセクション:

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

一次基本クラス

動的クラスの場合、オフセット0で仮想ポインターを共有する一意の基本クラス(存在する場合)。これは、存在する場合、最初の(直接基本クラスの順序で)非仮想動的基本クラスです。

動的クラス

仮想テーブルポインタを必要とするクラス(それまたはそのベースに1つ以上の仮想メンバー関数または仮想ベースクラスがあるため)。

4

2 に答える 2

8

これは次の標準の一部になりますstd::basesこれは、およびstd::direct_bases特性を介して中止されたTR2の一部でした。ドラフトTR2を含むコンパイラを使用している場合は、これをサポートしている可能性があります。たとえば、GCC4.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>

(デマングラーは私自身のものです。他の場所で見たことがあるかもしれません。)

私はあなたが適切な「多形性であり、正確にゼロまたは1つの塩基を持っている」特性を自分で構築できると信じています。

于 2013-02-28T20:48:18.230 に答える
0

以下は、C ++ 11のみで役立つことを行うための、徹底的にテストされていないワイルドな試みです(実際には、C ++ 11の機能は実際には必要ありません、この方法で作成する方が簡単です)。

ただし、この特性は、「isprimarybaseclassof」プロパティの推移閉包のみをチェックします。クラスが別のクラスの直接基本クラスであるかどうかを確認する非侵入的な方法を理解できませんでした。

#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!");
}
于 2013-02-28T21:12:37.453 に答える