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.

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