Detectando em C ++ se um tipo está definido: pré-declarando as coisas que você deseja investigar

Na última vez , usamos o SFINAE para detectar se um tipo tinha uma definição, e o usamos em combinação com if constexpr e lambdas genéricas, para que o código possa usar o tipo se for definido, enquanto continua sendo aceito pelo compilador (e sendo descartado ) se o tipo não estiver definido.

No entanto, nosso uso teve alguns problemas, alguns pequenos aborrecimentos, outros mais frustrantes.

  • Você tinha que dizer struct o tempo todo.
  • Se o tipo não existir, o ato de nomeá-lo fará com que o tipo seja injetado no espaço para nome atual , não no espaço para nome em que você esperava que o tipo estivesse.
  • Você deve usar a técnica struct com um nome não qualificado. Você não pode usá-lo para analisar um tipo que não importou para o espaço para nome atual.

Podemos resolver todos os três problemas com uma única solução: Pré-declare o tipo no espaço para nome desejado.



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

Depois de fazer isso, você não precisa dizer struct porque a estrutura foi definitivamente declarada. Seu uso como um parâmetro do tipo de modelo em call_if_defined não criará uma nova declaração, porque ela já foi declarada. E como foi declarado, você pode acessá-lo por meio de seu nome não qualificado, seu nome completo do espaço para nome ou qualquer outra coisa. Também um alias de tipo ou tipo dependente. (Desculpe, esses não estão no meio.)

 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 aqueles que seguem a série desde o início, você deve ter notado que o método call_if_defined não é exatamente o mesmo que a versão que escrevemos anteriormente. A nova versão suporta vários parâmetros de tipo e chama o lambda apenas se todos os tipos estiverem definidos.

Vamos dar uma olhada:

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

Os parênteses duplos no if constexpr ((...)) parecem estranhos, mas são necessários. Os parênteses externos são requeridos pela instrução if constexpr e os parênteses internos são requeridos pela expressão fold . A expressão da dobra se expande para

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

A chamada do lambda usa uma expansão do pacote de parâmetros :

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

Isso se expande para

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

onde o static_cast<T*>(nullptr) é repetido uma vez para cada tipo.

Como observei anteriormente, podemos usar esta função para chamar um lambda se todos os tipos estiverem 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); }); } 

O C ++ 20 permite que você escreva isso 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 permite que você nomeie o tipo de modelo, poupando assim o trabalho de ter que derivá-lo novamente jogando std::decay_t games.

Da próxima vez , usaremos isso como trampolim e estenderemos o padrão.



Nota para aqueles que chegaram aqui por meio de um mecanismo de pesquisa : esta é a última parte da parte principal da série, mas ainda há outras por vir. Para os impacientes, aqui estão as coisas para copiar e colar:

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

A propósito, temos uma vaga legal [Dublin]


A Havok está na vanguarda da inovação em desenvolvimento de jogos e 3D interativo há mais de uma década. Como parte da Cognition, a equipe responsável pelo HoloLens, agora estamos combinando esse conhecimento com o poder da Nuvem do Azure para desenvolver muitos novos serviços interessantes que impulsionam experiências de Realidade Mista, como o recentemente anunciado serviço de Renderização Remota do Azure. Somos apaixonados pela convergência das tecnologias de AR, VR e nuvem para permitir a criação de experiências inovadoras de realidade mista.

Trabalhando em Havok:

  • Você trabalhará em pequenas equipes focadas com desenvolvedores talentosos
  • Você terá a oportunidade de trabalhar com novas tecnologias em uma ampla gama de plataformas e dispositivos de hardware de ponta
  • Você trabalhará na solução de problemas técnicos desafiadores com amplo escopo
  • Você colaborará com equipes talentosas em todo o mundo

Responsabilidades


  • Projete, desenvolva, teste e forneça código C ++ multiplataforma eficiente, limpo e de alta qualidade
  • Desenvolver serviços do Azure altamente escalonáveis
  • Trabalhe diretamente com clientes internos e externos para impulsionar o desenvolvimento de produtos

Qualificações


  • Habilidades de codificação e depuração em C ++
  • Capacidade de trabalhar em um ambiente de equipe em uma base de código compartilhada
  • Experiência com tecnologias de nuvem e serviços distribuídos (por exemplo, Lote do Azure, Armazenamento de Blob do Azure, Docker, Telemetria)

Pontos de bônus


Existem muitas outras habilidades que não são necessárias, mas são valiosas para toda a equipe e incluem:

  • C #, ASP.Net, JavaScript, TypeScript, React
  • Unity, motores de jogo irreais ou relacionados
  • Experiência em 3D interativo, AR ou VR
  • Serviços de rede e back-end
  • Otimização de desempenho

Você pode obter mais informações e enviar seu currículo aqui .

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


All Articles