36 votes

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

J'ai besoin d'un type de trait qui sera vrai si le type de dérive à partir de rien, 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 de faire en quelque sorte mettre en œuvre que "is_inherit" trait struct?


Pourquoi?

Je suis en train d'élaborer un manuel de pile d'image builder pour Windows x64. Selon l' https://docs.microsoft.com/en-us/cpp/build/return-values-cpp de la documentation, si un type:

  • a une longueur de 1, 2, 4, 8, 16, 32, ou 64 bits;
  • n'a pas défini par l'utilisateur constructeur, destructeur, ou copie de l'opérateur d'assignation;
  • n'a pas privées ou protégées non-membres de données statiques;
  • n'a pas non données membres 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 sont pas aussi satisfaire à ces exigences;

alors sa valeur de retour est dans le registre RAX, sinon la fonction a un caché argument que je doit détecter et traiter.

C'est la définition d'un C++03 POD, cependant, en C++11, ce qui a changé:

Parce que la définition a changé dans le C++11 standard, nous ne recommandons pas l'utilisation d' std::is_pod pour ce test.

Jusqu'à maintenant, avec quelques conjugué traits je pouvais détecter si le type répond à la définition d'un C++03 POD ou pas. Toutefois, avec le C++17 le total des règles ont changé, et qui a brisé ma solution.

Si je peux en quelque sorte détecter si un type T a toute la classe de base, ma solution ne fonctionne de nouveau.

32voto

ecatmur Points 64173

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

Nous construisons d’abord un modèle de classe qui peut être converti en 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 peut être construit de manière globale à 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

9voto

Vittorio Romeo Points 2559

Je crois que de vérifier si "T provient de quelque chose" n'est pas possible, du moins pas dans une norme-conforme. Si vous utilisez cette technique pour vérifier si oui ou non un type est une GOUSSE/trivial, de les regrouper, il y a quelques traits de type qui pourrait vous aider:

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X