Detectar en C ++ si un tipo está definido: Predeclarar las cosas que desea sondear

La última vez , usamos SFINAE para detectar si un tipo tenía una definición, y lo usamos en combinación con if constexpr y lambdas genéricos para que el código pudiera usar el tipo si está definido, mientras el compilador todavía lo acepta (y se descarta ) si el tipo no está definido.

Sin embargo, nuestro uso tuvo algunos problemas, algunas molestias menores, algunas más frustrantes.

  • Tenías que decir struct todo el tiempo.
  • Si el tipo no existía, el acto de nombrarlo provocó que el tipo se inyectara en el espacio de nombres actual , no en el espacio de nombres en el que esperaba que estuviera el tipo.
  • Debe usar la técnica de struct con un nombre no calificado. No puede usarlo para sondear un tipo que no importó en el espacio de nombres actual.

Podemos solucionar los tres problemas con una única solución: Predeclarar el tipo en el espacio de nombres deseado.



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

Una vez que haya hecho esto, no necesita decir struct porque definitivamente la struct ha sido declarada. Su uso como parámetro de tipo de plantilla en call_if_defined no creará una nueva declaración, porque ya ha sido declarada. Y como se ha declarado, puede acceder a él a través de su nombre no calificado, su nombre de espacio de nombre completo o cualquier otro elemento intermedio. También un alias de tipo o tipo dependiente. (Lo siento, esos no están en el medio).

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

Para aquellos que han estado siguiendo la serie desde el principio, pueden haber notado que el método call_if_defined no es exactamente el mismo que la versión que escribimos anteriormente. La nueva versión admite múltiples parámetros de tipo y llama a lambda solo si todos los tipos están definidos.

Echemos un vistazo más de cerca:

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

Los paréntesis dobles en if constexpr ((...)) se ven raros, pero son obligatorios. Los paréntesis externos son requeridos por la declaración if constexpr , y los paréntesis internos son requeridos por la expresión de pliegue . La expresión de pliegue se expande a

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

La invocación de lambda utiliza una expansión de paquete de parámetros :

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

Esto se expande a

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

donde static_cast<T*>(nullptr) se repite una vez para cada tipo.

Como señalé anteriormente, podemos usar esta función para llamar a una lambda si todos los tipos están definidos:

 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 le permite escribir esto como

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

que le permite nombrar el tipo de plantilla, lo que le ahorra la molestia de tener que derivarlo jugando juegos std::decay_t .

La próxima vez , usaremos esto como trampolín y ampliaremos el patrón.



Nota para aquellos que llegaron aquí a través de un motor de búsqueda : esta es la última parte de la parte central de la serie, pero todavía hay partes por venir. Para los impacientes, aquí están las cosas para copiar y pegar:

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

Por cierto, tenemos una vacante genial [Dublín]


Havok ha estado a la vanguardia de la innovación en el desarrollo de juegos y 3D interactivo durante más de una década. Como parte de Cognition, el equipo responsable de HoloLens, ahora estamos combinando esa experiencia con el poder de la nube de Azure para desarrollar muchos servicios nuevos e interesantes que impulsan experiencias de realidad mixta, como el recientemente anunciado servicio Azure Remote Rendering. Nos apasiona la convergencia de AR, VR y tecnologías en la nube para permitir la creación de experiencias innovadoras de realidad mixta.

Trabajando en Havok:

  • Trabajarás en pequeños equipos enfocados con desarrolladores talentosos.
  • Tendrá la oportunidad de trabajar con nuevas tecnologías en una amplia gama de dispositivos y plataformas de hardware de vanguardia.
  • Trabajará para resolver problemas técnicos desafiantes con un amplio alcance
  • Colaborarás con equipos talentosos de todo el mundo.

Responsabilidades


  • Diseñe, desarrolle, pruebe y entregue código C ++ multiplataforma eficiente, limpio y de alta calidad
  • Desarrolle servicios de Azure altamente escalables
  • Trabajar directamente con clientes internos y externos para impulsar el desarrollo de productos.

Calificaciones


  • Habilidades de codificación y depuración de C ++
  • La capacidad de trabajar en un entorno de equipo en una base de código compartido
  • Experiencia con la nube y tecnologías de servicios distribuidos (por ejemplo, Azure Batch, Azure Blob Storage, Docker, Telemetry)

Puntos de bonificación


Hay muchas otras habilidades que no son necesarias, pero que son valiosas en todo el equipo y estas incluyen:

  • C #, ASP.Net, JavaScript, TypeScript, React
  • Unity, Unreal o motores de juegos relacionados
  • Experiencia en 3D interactivo, AR o VR
  • Servicios de red y backend
  • Optimización del rendimiento

Puede obtener más información y enviar su CV aquí .

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


All Articles