Beim letzten Mal haben wir SFINAE verwendet, um festzustellen, ob ein Typ eine Definition hat, und wir haben diese in Kombination mit
if constexpr
und generischen Lambdas verwendet, damit Code den Typ verwenden kann, wenn er definiert ist, während er vom Compiler noch akzeptiert wird (und verworfen wird) ) wenn der Typ nicht definiert ist.
Unsere Verwendung hatte jedoch einige Probleme, einige geringfügige Belästigungen, andere frustrierender.
- Man musste die ganze Zeit
struct
sagen. - Wenn der Typ nicht vorhanden war, wurde er durch die Benennung in den aktuellen Namespace eingefügt, nicht in den Namespace, in dem sich der Typ befinden sollte.
- Sie müssen die
struct
mit einem nicht qualifizierten Namen verwenden. Sie können damit keinen Typ prüfen, den Sie nicht in den aktuellen Namespace importiert haben.
Wir können alle drei Probleme mit einer einzigen Lösung beheben: Deklarieren Sie den Typ im gewünschten Namespace vorab.

Sobald Sie dies getan haben, müssen Sie nicht mehr
struct
sagen, da die struct definitiv deklariert wurde.
call_if_defined
es als Vorlagentypparameter in
call_if_defined
wird keine neue Deklaration erstellt, da diese bereits deklariert wurde. Und da es deklariert wurde, können Sie über seinen nicht qualifizierten Namen, seinen vollständigen Namespace-Namen oder irgendetwas dazwischen darauf zugreifen. Auch ein Typalias oder ein abhängiger Typ. (Sorry, die liegen nicht dazwischen.)
namespace app { void foo() { call_if_defined<awesome::special>([&](auto* p) {
Für diejenigen, die die Serie von Anfang an verfolgt haben, ist möglicherweise aufgefallen, dass die Methode
call_if_defined
nicht ganz mit der Version
call_if_defined
, die wir zuvor geschrieben haben. Die neue Version unterstützt mehrere Typparameter und ruft das Lambda nur auf, wenn alle Typen definiert sind.
Schauen wir uns das genauer an:
template<typename... T, typename TLambda> void call_if_defined(TLambda&& lambda) { if constexpr ((... && is_complete_type_v<T>)) { lambda(static_cast<T*>(nullptr)...); } }
Die Doppelklammern in if constexpr ((...)) sehen seltsam aus, sind aber erforderlich. Die äußeren Klammern werden von der
if constexpr
Anweisung benötigt, und die inneren Klammern werden vom
fold-Ausdruck benötigt . Der Fold-Ausdruck wird auf erweitert
if constexpr ( (is_complete_type_v<T1> && is_complete_type_v<T2> && ... is_complete_type_v<Tn>))
Der Aufruf des Lambda verwendet eine
Parameterpack-Erweiterung :
lambda(static_cast<T*>(nullptr)...);
Dies erweitert sich auf
lambda(static_cast<T1*>(nullptr), static_cast<T2*>(nullptr), ..., static_cast<Tn*>(nullptr));
Dabei wird der
static_cast<T*>(nullptr)
für jeden Typ einmal wiederholt.
Wie bereits erwähnt, können wir mit dieser Funktion ein Lambda aufrufen, wenn
alle Typen definiert sind:
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); }); }
In C ++ 20 können Sie dies als schreiben
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); }); }
Auf diese Weise können Sie den Vorlagentyp benennen und sich so die Mühe ersparen, ihn durch Spielen von
std::decay_t
Spielen erneut ableiten zu
std::decay_t
.
Nächstes Mal werden wir dies als Sprungbrett verwenden und das Muster erweitern.
Hinweis für diejenigen, die über eine Suchmaschine hierher gekommen sind : Dies ist der letzte Teil des Kernteils der Serie, aber es werden noch Teile folgen. Für die Ungeduldigen ist hier das Zeug zum Kopieren und Einfügen:
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)...); } }
Übrigens haben wir eine coole Stelle [Dublin]
Havok ist seit über einem Jahrzehnt auf dem neuesten Stand der Innovation in der Spieleentwicklung und im interaktiven 3D. Als Teil von Cognition, dem für HoloLens verantwortlichen Team, kombinieren wir dieses Know-how jetzt mit der Leistungsfähigkeit der Azure Cloud, um viele neue aufregende Dienste zu entwickeln, die Mixed Reality-Erlebnisse wie den kürzlich angekündigten Azure Remote Rendering-Dienst ermöglichen. Wir sind begeistert von der Konvergenz von AR-, VR- und Cloud-Technologien, um bahnbrechende Mixed Reality-Erlebnisse zu schaffen.
Arbeiten in Havok:- Sie arbeiten in kleinen, fokussierten Teams mit talentierten Entwicklern
- Sie haben die Möglichkeit, mit neuen Technologien auf einer Vielzahl von hochmodernen Hardwareplattformen und -geräten zu arbeiten
- Sie arbeiten an der Lösung herausfordernder technischer Probleme mit großem Umfang
- Sie werden mit talentierten Teams auf der ganzen Welt zusammenarbeiten
Verantwortlichkeiten
- Entwerfen, entwickeln, testen und liefern Sie hochwertigen, effizienten und sauberen C ++ - Code für mehrere Plattformen
- Entwickeln Sie hoch skalierbare Azure-Dienste
- Arbeiten Sie direkt mit internen und externen Kunden zusammen, um die Produktentwicklung voranzutreiben
Qualifikationen
- C ++ - Codierungs- und Debugging-Kenntnisse
- Die Fähigkeit, in einer Teamumgebung auf einer gemeinsam genutzten Codebasis zu arbeiten
- Erfahrung mit Cloud- und verteilten Servicetechnologien (z. B. Azure Batch, Azure Blob-Speicher, Docker, Telemetrie)
Bonuspunkte
Es gibt viele andere Fähigkeiten, die nicht erforderlich sind, aber im gesamten Team wertvoll sind. Dazu gehören:
- C #, ASP.Net, JavaScript, TypeScript, Reagieren
- Unity, Unreal oder verwandte Spiel-Engines
- Erfahrung in interaktivem 3D, AR oder VR
- Netzwerk- und Backend-Dienste
- Leistungsoptimierung
Weitere Informationen und Ihren Lebenslauf erhalten Sie
hier .