Avec C++17 est-il possible de détecter si une structure / classe a une base?

J'ai besoin d'un trait de type qui sera true si le type donné dérive de n'importe quoi, et false sinon.

Par exemple:

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
}

Est-il possible d'implémenter d'une manière ou d'une autre cette structure de trait "is_inherit"?


Pourquoi?

Je développe un générateur de cadre de pile manuelle pour Windows x64. Selon le https://docs.microsoft.com/en-us/cpp/build/return-values-cpp documentation, si un type:

  • a une longueur de 1, 2, 4, 8, 16, 32, ou 64 bits;
  • n'a aucun constructeur, destructeur ou opérateur d'affectation de copie défini par l'Utilisateur;
  • n'a pas de membres de données non statiques privés ou protégés;
  • n'a pas de membres de données non statiques de type de référence;
  • n'a pas de classes de base;
  • n'a pas de fonctions virtuelles;
  • et n'a pas de membres de données qui ne répondent pas également à ces exigences;

Alors sa valeur de retour est dans le registre RAX, sinon la fonction a un argument caché que je dois détecter et de la poignée.

C'était la définition D'un POD C++03, mais en C++11 cela a changé:

Étant donné que la définition a changé dans la norme C++11, nous ne recommandons pas d'utiliser std::is_pod pour ce test.

Jusqu'à présent, avec quelques traits conjugués, je pouvais détecter si le type répondait à la définition D'un POD C++03 ou non. Cependant, avec C++17, les règles d'agrégation ont changé, et cela a brisé ma solution.

Si je peux en quelque sorte détecter si un type T en a classe de base, ma solution fonctionnera à nouveau.

37
demandé sur Boann 2017-09-13 13:45:51

2 réponses

Oui, c'est possible, du moins pour les agrégats.

Tout d'abord, nous construisons un modèle de classe qui est convertible à n'importe quelle base appropriée de son paramètre de modèle:

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

Ensuite, nous détectons si un paramètre de modèle T est constructible agrégé à partir d'une valeur de type any_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 {};

Exemple.

32
répondu ecatmur 2017-09-13 13:56:19

Je crois que vérifier si "T dérive de n'importe quoi" n'est pas possible, du moins pas d'une manière conforme aux normes. Si vous utilisez cette technique pour vérifier si un type est un POD/trivial/aggregate, il y a des traits de type qui pourraient vous aider:

9
répondu Vittorio Romeo 2017-09-13 11:29:53