Détecter en C ++ si un type est défini: prédéclarer les choses que vous voulez sonder

La dernière fois , nous avons utilisé SFINAE pour détecter si un type avait une définition, et nous l'avons utilisée en combinaison avec if constexpr et lambdas génériques afin que le code puisse utiliser le type s'il est défini, tout en étant accepté par le compilateur (et en étant rejeté ) si le type n'est pas défini.

Cependant, notre utilisation a eu quelques problèmes, certains ennuis mineurs, certains plus frustrants.

  • Il fallait dire struct tout le temps.
  • Si le type n'existait pas, le fait de le nommer a provoqué l'injection du type dans l'espace de noms actuel , pas l'espace de noms dans lequel vous vous attendiez à ce que le type se trouve.
  • Vous devez utiliser la technique struct avec un nom non qualifié. Vous ne pouvez pas l'utiliser pour sonder un type que vous n'avez pas importé dans l'espace de noms actuel.

Nous pouvons résoudre les trois problèmes avec une seule solution: prédéclarer le type dans l'espace de noms souhaité.



 // awesome.h namespace awesome { // might or might not contain struct special { ... }; } // your code namespace awesome { // ensure declarations for types we // conditionalize on. struct special; } 

Une fois que vous avez fait cela, vous n'avez plus besoin de dire struct car la structure a été définitivement déclarée. Votre utilisation en tant que paramètre de type de modèle dans call_if_defined ne créera pas de nouvelle déclaration, car elle a déjà été déclarée. Et comme il a été déclaré, vous pouvez y accéder via son nom non qualifié, son nom d'espace de noms complet ou quoi que ce soit entre les deux. Également un alias de type ou un type dépendant. (Désolé, ce n'est pas entre les deux.)

 namespace app { void foo() { call_if_defined<awesome::special>([&](auto* p) { // this code is compiled only if "awesome::special" // is defined. Create a local name for "special" // by inferring it from the dummy parameter. using special = std::decay_t<decltype(*p)>; // You can now use the local name "special" to access // the features of "awesome::special". special::do_something(); }); } } 

Pour ceux qui suivent la série depuis le début, vous avez peut-être remarqué que la méthode call_if_defined n'est pas tout à fait la même que la version que nous avons écrite plus tôt. La nouvelle version prend en charge plusieurs paramètres de type et appelle le lambda uniquement si tous les types sont définis.

Examinons de plus près:

 template<typename... T, typename TLambda> void call_if_defined(TLambda&& lambda) { if constexpr ((... && is_complete_type_v<T>)) { lambda(static_cast<T*>(nullptr)...); } } 

Les parenthèses doubles dans le if constexpr ((...)) ont l'air bizarre, mais elles sont obligatoires. Les parenthèses externes sont requises par l' if constexpr et les parenthèses internes sont requises par l' expression fold . L'expression de pli se développe pour

  if constexpr ( (is_complete_type_v<T1> && is_complete_type_v<T2> && ... is_complete_type_v<Tn>)) 

L'invocation du lambda utilise une extension de pack de paramètres :

  lambda(static_cast<T*>(nullptr)...); 

Cela s'étend à

  lambda(static_cast<T1*>(nullptr), static_cast<T2*>(nullptr), ..., static_cast<Tn*>(nullptr)); 

où le static_cast<T*>(nullptr) est répété une fois pour chaque type.

Comme je l'ai noté précédemment, nous pouvons utiliser cette fonction pour appeler un lambda si tous les types sont définis:

 void foo(Source const& source) { call_if_defined<special, magic>( [&](auto* p1, auto* p2) { using special = std::decay_t<decltype(*p1)>; using magic = std::decay_t<decltype(*p2)>; auto s = source.try_get<special>(); if (s) magic::add_magic(s); }); } 

C ++ 20 vous permet d'écrire ceci comme

 void foo(Source const& source) { call_if_defined<special, magic>( [&]<typename special, typename magic> (special*, magic*) { auto s = source.try_get<special>(); if (s) magic::add_magic(s); }); } 

ce qui vous permet de nommer le type de modèle, vous évitant ainsi d'avoir à le dériver en jouant aux jeux std::decay_t .

La prochaine fois , nous l'utiliserons comme tremplin et étendrons le motif.



Remarque pour ceux qui sont arrivés ici via un moteur de recherche : il s'agit de la dernière partie de la partie principale de la série, mais il reste encore des parties à venir. Pour les impatients, voici le truc à copier-coller:

 template<typename, typename = void> constexpr bool is_type_complete_v = false; template<typename T> constexpr bool is_type_complete_v <T, std::void_t<decltype(sizeof(T))>> = true; template<typename... T, typename TLambda> void call_if_defined(TLambda&& lambda) { if constexpr ((... && is_complete_type_v<T>)) { lambda(static_cast<T*>(nullptr)...); } } 

Soit dit en passant, nous avons une vacance cool [Dublin]


Havok est à la pointe de l'innovation dans le développement de jeux et la 3D interactive depuis plus d'une décennie. Dans le cadre de Cognition, l'équipe responsable de HoloLens, nous combinons maintenant cette expertise avec la puissance du cloud Azure pour développer de nombreux nouveaux services passionnants propulsant des expériences de réalité mixte telles que le service Azure Remote Rendering récemment annoncé. Nous sommes passionnés par la convergence des technologies AR, VR et cloud pour permettre la création d'expériences révolutionnaires de réalité mixte.

Travailler à Havok:

  • Vous travaillerez en petites équipes ciblées avec des développeurs talentueux
  • Vous aurez l'occasion de travailler avec de nouvelles technologies sur une gamme diversifiée de plates-formes et d'appareils matériels de pointe
  • Vous travaillerez sur la résolution de problèmes techniques difficiles avec une large portée
  • Vous collaborerez avec des équipes talentueuses à travers le monde

Responsabilités


  • Concevoir, développer, tester et fournir du code C ++ multiplateforme de haute qualité, efficace et propre
  • Développer des services Azure hautement évolutifs
  • Travailler directement avec les clients internes et externes pour piloter le développement de produits

Qualifications


  • Compétences en codage et débogage C ++
  • Une capacité à travailler en équipe sur une base de code partagée
  • Expérience avec les technologies de cloud et de services distribués (par exemple Azure Batch, Azure Blob Storage, Docker, Telemetry)

Points bonus


Il existe de nombreuses autres compétences qui ne sont pas requises, mais qui sont précieuses dans toute l'équipe, notamment:

  • C #, ASP.Net, JavaScript, TypeScript, React
  • Moteurs de jeux Unity, Unreal ou associés
  • Expérience en 3D interactive, AR ou VR
  • Services de mise en réseau et backend
  • Optimisation des performances

Vous pouvez obtenir plus d'informations et soumettre votre CV ici .

Source: https://habr.com/ru/post/fr459834/


All Articles