web-dev-qa-db-ja.com

C ++ 17では、構造体/クラスにベースがあるかどうかを検出できますか?

与えられた型が何かに由来する場合はtrue、そうでない場合はfalseとなる型特性が必要です。

例えば:

template<class T>
struct is_inherit
    //... logic of inheritance detection
    ;

template<class T>
void AppLogic(){
    if constexpr(is_inherit<T>::value) {
        puts("T has base");
        //...
    } else {
        puts("T doesn't have base");
        //...
    }
}

struct A {};
struct C {};
struct B: C {};

int main() {
    AppLogic<A>(); // print: T doesn't have base 
    AppLogic<B>(); // print: T has base
}

その「is_inherit」特性構造体を何らかの方法で実装することは可能ですか?


どうして?

Windows x64用の手動スタックフレームビルダーを開発しています。 https://docs.Microsoft.com/en-us/cpp/build/return-values-cpp ドキュメントによると、タイプが次の場合:

  • 長さは1、2、4、8、16、32、または64ビットです。
  • ユーザー定義のコンストラクタ、デストラクタ、またはコピー割り当て演算子はありません。
  • プライベートまたは保護された非静的データメンバーがありません。
  • 参照型の非静的データメンバーはありません。
  • 基本クラスはありません。
  • 仮想機能はありません。
  • これらの要件も満たさないデータメンバーはありません。

その戻り値はRAXレジスタにあります。それ以外の場合、関数には隠し引数があり、これを検出して処理する必要があります。

これは以前はC++ 03 PODの定義でしたが、C++ 11ではこれが変更されました。

C++ 11標準では定義が変更されているため、このテストにstd::is_podを使用することはお勧めしません。

これまで、いくつかの共役特性を使用して、型がC++ 03 PODの定義を満たしているかどうかを検出できました。ただし、C++ 17では集計ルールが変更されたため、ソリューションが壊れました。

タイプTに基本クラスがあるかどうかを何らかの方法で検出できれば、ソリューションは再び機能します。

37
Nyufu

はい、少なくとも集約に対しては可能です。

まず、テンプレートパラメータの適切なベースに変換可能なクラステンプレートを作成します。

template<class T>
struct any_base {
    operator T() = delete;
    template<class U, class = std::enable_if_t<std::is_base_of_v<U, T>>> operator U();
};

次に、テンプレートパラメータTany_base<T>型の値から構築可能な集約であるかどうかを検出します。

template<class, class = void> struct has_any_base : std::false_type {};
template<class T>
struct has_any_base<T, std::void_t<decltype(T{any_base<T>{}})>> : std::true_type {};

32
ecatmur

Tが何かに由来する」かどうかをチェックすることは、少なくとも標準に準拠した方法では不可能だと思います。この手法を使用して、型がPOD/trivial/aggregateであるかどうかを確認する場合、役立つ可能性のある型特性がいくつかあります。

9
Vittorio Romeo