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é.

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) {
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 .